/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "dwarf.hh"
#include "elf.hh"
#include "file_mng.hh"
#include "util.hh"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libgen.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

#define DW_TAM_BUF               64
#define DW_MAX_DIE_STACK        128
#define DW_MAX_NAMESPACE       1024
#define INC_BASE              16384
#define INC_CHILD               128
#define INC_SOURCE_FILES         32
#define INC_MULTI_SPEC          128
#define PATH_BUFFER            4096
#define INC_PROTO_PARAMS         16

#define MAX_COMPARE_RECUR_LEVEL  16
#define MARK_BAD_ADDR    0x7fffffff

// LOCAL TYPES
struct _multi_spec_
{
    int offset;
    int i_base;
};

//#define SHOW_LOCATION_EXPRESION_ERRORS

const dwarf_entity inline_names[]=
{
    {DW_INL_not_inlined, "not_inlined"},
    {DW_INL_inlined, "inlined"},
    {DW_INL_declared_not_inlined, "declared_not_inlined"},
    {DW_INL_declared_inlined, "declared_inlined"},
};
#define n_inline_names ((int)(sizeof(inline_names)/sizeof(inline_names[0])))

const dwarf_entity access_names[]=
{
    {DW_ACCESS_public, "public"},
    {DW_ACCESS_protected, "protected"},
    {DW_ACCESS_private, "private"},
};
#define n_access_names ((int)(sizeof(access_names)/sizeof(access_names[0])))

const dwarf_entity encoding_names[]=
{
    {DW_ATE_void, "void"},
    {DW_ATE_address, "address"},
    {DW_ATE_boolean, "boolean"},
    {DW_ATE_complex_float, "complex_float"},
    {DW_ATE_float, "float"},
    {DW_ATE_signed, "signed"},
    {DW_ATE_signed_char, "signed_char"},
    {DW_ATE_unsigned, "unsigned"},
    {DW_ATE_unsigned_char, "unsigned_char"},
    {DW_ATE_imaginary_float, "imaginary_float"},
    {DW_ATE_packed_decimal, "packed_decimal"},
    {DW_ATE_numeric_string, "numeric_string"},
    {DW_ATE_edited, "edited"},
    {DW_ATE_signed_fixed, "signed_fixed"},
    {DW_ATE_unsigned_fixed, "unsigned_fixed"},
    {DW_ATE_decimal_float, "decimal_float"},
};
#define n_encoding_names ((int)(sizeof(encoding_names)/sizeof(encoding_names[0])))

const dwarf_entity lang_names[]=
{
    {DW_LANG_C89, "C89"},
    {DW_LANG_C, "C"},
    {DW_LANG_Ada83, "Ada83"},
    {DW_LANG_C_plus_plus, "C++"},
    {DW_LANG_Cobol74, "Cobol74"},
    {DW_LANG_Cobol85, "Cobol85"},
    {DW_LANG_Fortran77, "Fortran77"},
    {DW_LANG_Fortran90, "Fortran90"},
    {DW_LANG_Pascal83, "Pascal83"},
    {DW_LANG_Modula2, "Modula2"},
    {DW_LANG_Java, "Java"},
    {DW_LANG_C99, "C99"},
    {DW_LANG_Ada95, "Ada95"},
    {DW_LANG_Fortran95, "Fortran95"},
    {DW_LANG_PL1, "PL1"},
    {DW_LANG_Objc, "Objc"},
    {DW_LANG_ObjC_plus_plus, "ObjC++"},
    {DW_LANG_UPC, "UPC"},
    {DW_LANG_D, "D"},
    {DW_LANG_Mips_Assembler, "Assembler"},
};
#define n_lang_names ((int)(sizeof(lang_names)/sizeof(lang_names[0])))

const dwarf_entity tag_names[]=
{
    {DW_TAG_array_type, "array_type"},
    {DW_TAG_class_type, "class_type"},
    {DW_TAG_entry_point, "entry_point"},
    {DW_TAG_enumeration_type, "enumeration_type"},
    {DW_TAG_formal_parameter, "formal_parameter"},
    {DW_TAG_imported_declaration, "imported_declaration"},
    {DW_TAG_label, "label"},
    {DW_TAG_lexical_block, "lexical_block"},
    {DW_TAG_member, "member"},
    {DW_TAG_pointer_type, "pointer_type"},
    {DW_TAG_reference_type, "reference_type"},
    {DW_TAG_compile_unit, "compile_unit"},
    {DW_TAG_string_type, "string_type"},
    {DW_TAG_structure_type, "structure_type"},
    {DW_TAG_subroutine_type, "subroutine_type"},
    {DW_TAG_typedef, "typedef"},
    {DW_TAG_union_type, "union_type"},
    {DW_TAG_unspecified_parameters, "unspecified_parameters"},
    {DW_TAG_variant, "variant"},
    {DW_TAG_common_block, "common_block"},
    {DW_TAG_common_inclusion, "common_inclusion"},
    {DW_TAG_inheritance, "inheritance"},
    {DW_TAG_inlined_subroutine, "inlined_subroutine"},
    {DW_TAG_module, "module"},
    {DW_TAG_ptr_to_member_type, "ptr_to_member_type"},
    {DW_TAG_set_type, "set_type"},
    {DW_TAG_subrange_type, "subrange_type"},
    {DW_TAG_with_stmt, "with_stmt"},
    {DW_TAG_access_declaration, "access_declaration"},
    {DW_TAG_base_type, "base_type"},
    {DW_TAG_catch_block, "catch_block"},
    {DW_TAG_const_type, "const_type"},
    {DW_TAG_constant, "constant"},
    {DW_TAG_enumerator, "enumerator"},
    {DW_TAG_file_type, "file_type"},
    {DW_TAG_friend, "friend"},
    {DW_TAG_namelist, "namelist"},
    {DW_TAG_namelist_item, "namelist_item"},
    {DW_TAG_packed_type, "packed_type"},
    {DW_TAG_subprogram, "subprogram"},
    {DW_TAG_template_type_parameter, "template_type_parameter"},
    {DW_TAG_template_value_parameter, "template_value_parameter"},
    {DW_TAG_thrown_type, "thrown_type"},
    {DW_TAG_try_block, "try_block"},
    {DW_TAG_variant_part, "variant_part"},
    {DW_TAG_variable, "variable"},
    {DW_TAG_volatile_type, "volatile_type"},
    {DW_TAG_dwarf_procedure, "dwarf_procedure"},
    {DW_TAG_restrict_type, "restrict_type"},
    {DW_TAG_interface_type, "interface_type"},
    {DW_TAG_namespace, "namespace"},
    {DW_TAG_imported_module, "imported_module"},
    {DW_TAG_unspecified_type, "unspecified_type"},
    {DW_TAG_partial_unit, "partial_unit"},
    {DW_TAG_imported_unit, "imported_unit"},
    {DW_TAG_mutable_type, "mutable_type"},
    {DW_TAG_condition, "condition"},
    {DW_TAG_shared_type, "shared_type"},
    {DW_TAG_MIPS_loop, "MIPS_loop"},
    {DW_TAG_format_label, "format_label"},
    {DW_TAG_function_template, "function_template"},
    {DW_TAG_class_template, "class_template"},
};
#define n_tag_names ((int)(sizeof(tag_names)/sizeof(tag_names[0])))

const dwarf_entity attr_names[]=
{
    {DW_AT_sibling, "sibling"},
    {DW_AT_location, "location"},
    {DW_AT_name, "name"},
    {DW_AT_ordering, "ordering"},
    {DW_AT_subscr_data, "subscr_data"},
    {DW_AT_byte_size, "byte_size"},
    {DW_AT_bit_offset, "bit_offset"},
    {DW_AT_bit_size, "bit_size"},
    {DW_AT_element_list, "element_list"},
    {DW_AT_stmt_list, "stmt_list"},
    {DW_AT_low_pc, "low_pc"},
    {DW_AT_high_pc, "high_pc"},
    {DW_AT_language, "language"},
    {DW_AT_member, "member"},
    {DW_AT_discr, "discr"},
    {DW_AT_discr_value, "discr_value"},
    {DW_AT_visibility, "visibility"},
    {DW_AT_import, "import"},
    {DW_AT_string_length, "string_length"},
    {DW_AT_common_reference, "common_reference"},
    {DW_AT_comp_dir, "comp_dir"},
    {DW_AT_const_value, "const_value"},
    {DW_AT_containing_type, "containing_type"},
    {DW_AT_default_value, "default_value"},
    {DW_AT_inline, "inline"},
    {DW_AT_is_optional, "is_optional"},
    {DW_AT_lower_bound, "lower_bound"},
    {DW_AT_producer, "producer"},
    {DW_AT_prototyped, "prototyped"},
    {DW_AT_return_addr, "return_addr"},
    {DW_AT_start_scope, "start_scope"},
    {DW_AT_bit_stride, "bit_stride"},
    {DW_AT_upper_bound, "upper_bound"},
    {DW_AT_abstract_origin, "abstract_origin"},
    {DW_AT_accessibility, "accessibility"},
    {DW_AT_address_class, "address_class"},
    {DW_AT_artificial, "artificial"},
    {DW_AT_base_types, "base_types"},
    {DW_AT_calling_convention, "calling_convention"},
    {DW_AT_count, "count"},
    {DW_AT_data_member_location, "data_member_location"},
    {DW_AT_decl_column, "decl_column"},
    {DW_AT_decl_file, "decl_file"},
    {DW_AT_decl_line, "decl_line"},
    {DW_AT_declaration, "declaration"},
    {DW_AT_discr_list, "discr_list"},
    {DW_AT_encoding, "encoding"},
    {DW_AT_external, "external"},
    {DW_AT_frame_base, "frame_base"},
    {DW_AT_friend, "friend"},
    {DW_AT_identifier_case, "identifier_case"},
    {DW_AT_macro_info, "macro_info"},
    {DW_AT_namelist_item, "namelist_item"},
    {DW_AT_priority, "priority"},
    {DW_AT_segment, "segment"},
    {DW_AT_specification, "specification"},
    {DW_AT_static_link, "static_link"},
    {DW_AT_type, "type"},
    {DW_AT_use_location, "use_location"},
    {DW_AT_variable_parameter, "variable_parameter"},
    {DW_AT_virtuality, "virtuality"},
    {DW_AT_vtable_elem_location, "vtable_elem_location"},
    {DW_AT_allocated, "allocated"},
    {DW_AT_associated, "associated"},
    {DW_AT_data_location, "data_location"},
    {DW_AT_byte_stride, "byte_stride"},
    {DW_AT_entry_pc, "entry_pc"},
    {DW_AT_use_UTF8, "use_UTF8"},
    {DW_AT_extension, "extension"},
    {DW_AT_ranges, "ranges"},
    {DW_AT_trampoline, "trampoline"},
    {DW_AT_call_column, "call_column"},
    {DW_AT_call_file, "call_file"},
    {DW_AT_call_line, "call_line"},
    {DW_AT_description, "description"},
    {DW_AT_binary_scale, "binary_scale"},
    {DW_AT_decimal_scale, "decimal_scale"},
    {DW_AT_small, "small"},
    {DW_AT_decimal_sign, "decimal_sign"},
    {DW_AT_digit_count, "digit_count"},
    {DW_AT_picture_string, "picture_string"},
    {DW_AT_mutable, "mutable"},
    {DW_AT_threads_scaled, "threads_scaled"},
    {DW_AT_explicit, "explicit"},
    {DW_AT_object_pointer, "object_pointer"},
    {DW_AT_endianity, "endianity"},
    {DW_AT_elemental, "elemental"},
    {DW_AT_pure, "pure"},
    {DW_AT_recursive, "recursive"},
    {DW_AT_MIPS_fde, "MIPS_fde"},
    {DW_AT_MIPS_loop_begin, "MIPS_loop_begin"},
    {DW_AT_MIPS_tail_loop_begin, "MIPS_tail_loop_begin"},
    {DW_AT_MIPS_epilog_begin, "MIPS_epilog_begin"},
    {DW_AT_MIPS_loop_unroll_factor, "MIPS_loop_unroll_factor"},
    {DW_AT_MIPS_software_pipeline_depth, "MIPS_software_pipeline_depth"},
    {DW_AT_MIPS_linkage_name, "MIPS_linkage_name"},
    {DW_AT_MIPS_stride, "MIPS_stride"},
    {DW_AT_MIPS_abstract_name, "MIPS_abstract_name"},
    {DW_AT_MIPS_clone_origin, "MIPS_clone_origin"},
    {DW_AT_MIPS_has_inlines, "MIPS_has_inlines"},
    {DW_AT_MIPS_stride_byte, "MIPS_stride_byte"},
    {DW_AT_MIPS_stride_elem, "MIPS_stride_elem"},
    {DW_AT_MIPS_ptr_dopetype, "MIPS_ptr_dopetype"},
    {DW_AT_MIPS_allocatable_dopetype, "MIPS_allocatable_dopetype"},
    {DW_AT_MIPS_assumed_shape_dopetype, "MIPS_assumed_shape_dopetype"},
    {DW_AT_MIPS_assumed_size, "MIPS_assumed_size"},
    {DW_AT_sf_names, "sf_names"},
    {DW_AT_src_info, "src_info"},
    {DW_AT_mac_info, "mac_info"},
    {DW_AT_src_coords, "src_coords"},
    {DW_AT_body_begin, "body_begin"},
    {DW_AT_body_end, "body_end"},
};
#define n_attr_names ((int)(sizeof(attr_names)/sizeof(attr_names[0])))

int dwarf_base::add_child(int i_child_)
{
    int i=util::inc_vector(i_child, n_child, max_child, INC_CHILD);
    i_child[i]=i_child_;
    return 1;
}

void dwarf_base::del_children()
{
    if(i_child) i_child=(int*)realloc(i_child, 0);
    n_child=max_child=0;
}

void dwarf_base::copy_attribs_from(dwarf_base *orig)
{
    i_name=orig->i_name;
    i_source=orig->i_source;
    i_namespace=orig->i_namespace;
    i_attr=orig->i_attr;
    type=orig->type;
    line=orig->line;
    size=orig->size;
    value.all=orig->value.all;
    value2.all=orig->value2.all;
    bit.all=orig->bit.all;
    i_subtype=orig->i_subtype;
}


CLASS_INIT(dwarf); // DWARF CLASS

dwarf::dwarf()
{
    CLASS_CTOR(dwarf);
    ctor();

    // doc
    doc=new string_index;
}

dwarf::~dwarf()
{
    CLASS_DTOR(dwarf);
    dtor();

    // doc
    if(doc) {delete doc; doc=NULL;}
}

void dwarf::ctor()
{
    // elf and dwarf
    elfname=NULL;
    fd=-1;
    dw=NULL;

    // navigation
    pointer_i=pointer_max=-1;

    // bases
    util::ctor_vector(base, n_base, max_base);
    memset(&root, 0, sizeof(dwarf_base));
}

void dwarf::dtor()
{
    // end analysis
    analyze_end();

    // bases
    for(int i=0; i<n_base; i++) base[i].del_children();
    util::dtor_vector(base, n_base, max_base);
}

char *dwarf::entity_string(const dwarf_entity *list, int n_list, int code, char *buf)
{
    int i;
    for(i=0; i<n_list; i++) if(list[i].code==code) {snprintf(buf, DW_TAM_BUF, "%s", list[i].name); break;}
    if(i==n_list) snprintf(buf, DW_TAM_BUF, "%#x", code);
    return buf;
}

char *dwarf::entity_tag_string(int code, char *buf)
{
    int i;
    for(i=0; i<n_tag_names; i++) if(tag_names[i].code==code) {snprintf(buf, DW_TAM_BUF, "%s", tag_names[i].name); break;}
    if(i==n_tag_names) snprintf(buf, DW_TAM_BUF, "%#x (! tag defined !)", code);
    return buf;
}

char *dwarf::entity_string(const dwarf_entity *list, int n_list, int code)
{
    for(int i=0; i<n_list; i++) if(list[i].code==code) return (char*)list[i].name;
    return NULL;
}

char *dwarf::entity_tag_string(int code)
{
    for(int i=0; i<n_tag_names; i++) if(tag_names[i].code==code) return (char*)tag_names[i].name;
    return NULL;
}

char *dwarf::entity_encoding_string(int code)
{
    for(int i=0; i<n_encoding_names; i++) if(encoding_names[i].code==code) return (char*)encoding_names[i].name;
    return NULL;
}

unsigned int dwarf::addr_from_expression(Dwarf_Op *expr, unsigned int n_expr)
{
    unsigned int addr=MARK_BAD_ADDR;
    if(n_expr==1)
	switch(expr[0].atom)
	{
	case DW_OP_const1u:
	case DW_OP_const2u:
	case DW_OP_const4u:
	case DW_OP_constu:
	case DW_OP_addr:
	case DW_OP_fbreg:
	case DW_OP_plus_uconst:
	    addr=expr[0].number;
	    break;
	case DW_OP_reg0:
#ifdef SHOW_LOCATION_EXPRESION_ERRORS
	    ERROR("TODO register0");
#endif
	    break;
	default: ;
#ifdef SHOW_LOCATION_EXPRESION_ERRORS
	    dump_expression(expr, n_expr);
	    ERROR("TODO expression 0x%02x", expr[0].atom);
#endif
	}
    else
    {
#ifdef SHOW_LOCATION_EXPRESION_ERRORS
	dump_expression(expr, n_expr);
	ERROR("TODO expression more than one component");
#endif
    }
    return addr;
}

void dwarf::dump_expression(Dwarf_Op *expr, unsigned int n_expr)
{
    printf("EXPR\n");
    for(unsigned int i=0; i<n_expr; i++)
	printf("\t%02x %08x %08x %08x\n", expr[i].atom, (unsigned)expr[i].number, (unsigned)expr[i].number2, (unsigned)expr[i].offset);
}

bool dwarf::dump_dies(Dwarf *dw, Dwarf_Die *die, int level, int recur, FILE *out)
{
    const char *str;
    char buf[DW_TAM_BUF];
    int tag=dwarf_tag(die), attr_list[92], n_attr_list, integ;
    Dwarf_Attribute attr;
    Dwarf_Word uval;

    // tag
    fprintf(out, "%*s%s\n", level*5, "", entity_tag_string(tag, buf));

    // offsets
#define DW_SHOW_OFF
#ifdef DW_SHOW_OFF
    fprintf(out, "%*s Offset    : %lld\n", level*5, "", (long long int)dwarf_dieoffset(die));
#endif
#ifdef DW_SHOW_CUOFF
    fprintf(out, "%*s CU offset : %lld\n", level*5, "", (long long int)dwarf_cuoffset(die));
#endif

    // attrs
    attr_list[0]=DW_AT_stmt_list;
    attr_list[1]=DW_AT_low_pc;
    attr_list[2]=DW_AT_high_pc;
    attr_list[3]=DW_AT_sibling;
    attr_list[4]=DW_AT_ranges;
    attr_list[5]=DW_AT_frame_base;
    n_attr_list=6;

    if((str=dwarf_diename(die)))
    {
	fprintf(out, "%*s Name      : %s\n", level*5, "", str);
	attr_list[n_attr_list++]=DW_AT_name;
    }
    if(dwarf_hasattr(die, DW_AT_MIPS_linkage_name))
    {
	if(dwarf_attr(die, DW_AT_MIPS_linkage_name, &attr) && (str=dwarf_formstring(&attr)))
	{
	    fprintf(out, "%*s Link name : %s\n", level*5, "", str);
	    attr_list[n_attr_list++]=DW_AT_MIPS_linkage_name;
	}
    }
    if(dwarf_hasattr(die, DW_AT_byte_size) && (integ=dwarf_bytesize(die))!=-1)
    {
	fprintf(out, "%*s Byte size : %d\n", level*5, "", integ);
	attr_list[n_attr_list++]=DW_AT_byte_size;
    }
    if(dwarf_hasattr(die, DW_AT_comp_dir))
    {
	if(dwarf_attr(die, DW_AT_comp_dir, &attr) && (str=dwarf_formstring(&attr)))
	{
	    fprintf(out, "%*s Directory : %s\n", level*5, "", str);
	    attr_list[n_attr_list++]=DW_AT_comp_dir;
	}
    }
    if(dwarf_hasattr(die, DW_AT_producer))
    {
	if(dwarf_attr(die, DW_AT_producer, &attr) && (str=dwarf_formstring(&attr)))
	    fprintf(out, "%*s Producer  : %s\n", level*5, "", str);
	attr_list[n_attr_list++]=DW_AT_producer;
    }
    if(dwarf_hasattr(die, DW_AT_language) && (integ=dwarf_srclang(die))!=-1)
    {
	fprintf(out, "%*s Language  : %s\n", level*5, "", entity_string(lang_names, n_lang_names, integ, buf));
	attr_list[n_attr_list++]=DW_AT_language;
    }
    if(dwarf_hasattr(die, DW_AT_encoding))
    {
	if(dwarf_attr(die, DW_AT_encoding, &attr) && dwarf_formudata(&attr, &uval)!=-1)
	{
	    fprintf(out, "%*s Encoding  : %s\n", level*5, "", entity_string(encoding_names, n_encoding_names, (int)uval, buf));
	    attr_list[n_attr_list++]=DW_AT_encoding;
	}
    }
    if(dwarf_hasattr(die, DW_AT_decl_file) && (str=dwarf_decl_file(die)))
    {
	fprintf(out, "%*s File/Lin/C: %s", level*5, "", str);
	if(dwarf_hasattr(die, DW_AT_decl_line) && dwarf_decl_line(die, &integ)!=-1)
	{
	    fprintf(out, ":%d", integ);
	    if(dwarf_hasattr(die, DW_AT_decl_column) && dwarf_decl_column(die, &integ)!=-1)
	    {
		fprintf(out, ":%d", integ);
		attr_list[n_attr_list++]=DW_AT_decl_column;
	    }
	    attr_list[n_attr_list++]=DW_AT_decl_line;
	}
	attr_list[n_attr_list++]=DW_AT_decl_file;
	fprintf(out, "\n");
    }
    if(dwarf_hasattr(die, DW_AT_accessibility))
    {
	if(dwarf_attr(die, DW_AT_accessibility, &attr) && dwarf_formudata(&attr, &uval)!=-1)
	{
	    fprintf(out, "%*s Accessibil: %s\n", level*5, "", entity_string(access_names, n_access_names, (int)uval, buf));
	    attr_list[n_attr_list++]=DW_AT_accessibility;
	}
    }
    if(dwarf_hasattr(die, DW_AT_location))
    {
	Dwarf_Op *expr;
	unsigned int exprlen, addr;
	if(dwarf_attr(die, DW_AT_location, &attr) &&
	   dwarf_getlocation(&attr, &expr, &exprlen)!=-1 && (addr=addr_from_expression(expr, exprlen))!=MARK_BAD_ADDR)
	{
	    fprintf(out, "%*s Location  : %08x\n", level*5, "", addr);
	    attr_list[n_attr_list++]=DW_AT_location;
	}
    }
    if(dwarf_hasattr(die, DW_AT_data_member_location))
    {
	Dwarf_Op *expr;
	unsigned int exprlen, addr;
	if(dwarf_attr(die, DW_AT_data_member_location, &attr) &&
	   dwarf_getlocation(&attr, &expr, &exprlen)!=-1 && (addr=addr_from_expression(expr, exprlen))!=MARK_BAD_ADDR)
	{
	    fprintf(out, "%*s DMLocation: 0x%08x\n", level*5, "", addr);
	    attr_list[n_attr_list++]=DW_AT_data_member_location;
	}
    }
    if(dwarf_hasattr(die, DW_AT_declaration))
    {
	bool flag;
	if(dwarf_attr(die, DW_AT_declaration, &attr) && dwarf_formflag(&attr, &flag)!=-1)
	{
	    fprintf(out, "%*s Declaratio: %d\n", level*5, "", flag);
	    attr_list[n_attr_list++]=DW_AT_declaration;
	}
    }
    if(dwarf_hasattr(die, DW_AT_external))
    {
	bool flag;
	if(dwarf_attr(die, DW_AT_external, &attr) && dwarf_formflag(&attr, &flag)!=-1)
	{
	    fprintf(out, "%*s External  : %d\n", level*5, "", flag);
	    attr_list[n_attr_list++]=DW_AT_external;
	}
    }
    if(dwarf_hasattr(die, DW_AT_artificial))
    {
	bool flag;
	if(dwarf_attr(die, DW_AT_artificial, &attr) && dwarf_formflag(&attr, &flag)!=-1)
	{
	    fprintf(out, "%*s Artificial: %d\n", level*5, "", flag);
	    attr_list[n_attr_list++]=DW_AT_artificial;
	}
    }
    if(dwarf_hasattr(die, DW_AT_specification))
    {
	if(dwarf_attr(die, DW_AT_specification, &attr))
	{
	    Dwarf_Die die_spec;
	    if(!dwarf_formref_die(&attr, &die_spec)) ERROR_RX(false, "dwarf_formref_die");
	    fprintf(out, "%*s Specificat: %lld\n", level*5, "", dwarf_dieoffset(&die_spec));
	    attr_list[n_attr_list++]=DW_AT_specification;
	}
    }
    if(dwarf_hasattr(die, DW_AT_upper_bound))
    {
	Dwarf_Sword val;
	if(dwarf_attr(die, DW_AT_upper_bound, &attr) && dwarf_formsdata(&attr, &val)!=-1)
	{
	  fprintf(out, "%*s Upper Boun: %d\n", level*5, "", (int)val);
	    attr_list[n_attr_list++]=DW_AT_upper_bound;
	}
    }
    if(dwarf_hasattr(die, DW_AT_inline))
    {
	if(dwarf_attr(die, DW_AT_inline, &attr) && dwarf_formudata(&attr, &uval)!=-1)
	{
	    fprintf(out, "%*s Inline    : %s\n", level*5, "", entity_string(inline_names, n_inline_names, (int)uval, buf));
	    attr_list[n_attr_list++]=DW_AT_inline;
	}
    }
    if(dwarf_hasattr(die, DW_AT_type) && recur)
    {
	Dwarf_Die die_type;
	if(dwarf_attr(die, DW_AT_type, &attr))
	{
	    fprintf(out, "%*s Type      :\n", level*5, "");
	    if(!dwarf_formref_die(&attr, &die_type) || !dump_dies(dw, &die_type, level+1, 0/*recur*/, out)) ERROR_RX(false, "dwarf_offdie (type)");
	    attr_list[n_attr_list++]=DW_AT_type;
	}
    }
    if(dwarf_hasattr(die, DW_AT_import))
    {
	Dwarf_Die die_import;
	if(dwarf_attr(die, DW_AT_import, &attr) && dwarf_formref_die(&attr, &die_import))
	{
	    fprintf(out, "%*s Import    : %lld\n", level*5, "", dwarf_dieoffset(&die_import));
	    attr_list[n_attr_list++]=DW_AT_import;
	}
    }

    // rest of attrs not printed
    int print_attrs=0;
    for(int cnt=0; cnt<(int)n_attr_names; ++cnt)
	if(dwarf_hasattr(die, attr_names[cnt].code))
	{
	    int cnt2;
	    for(cnt2=0; cnt2<n_attr_list; cnt2++) if(attr_list[cnt2]==attr_names[cnt].code) break;
	    if(cnt2==n_attr_list)
	    {
		if(!print_attrs++) fprintf(out, "%*s Attrs     :", level*5, "");
		fprintf(out, " %s", attr_names[cnt].name);
	    }
	}
    if(print_attrs) fprintf(out, "\n");

    if(recur)
    {
	Dwarf_Die child;
	if(dwarf_haschildren(die) && !dwarf_child(die, &child) && !dump_dies(dw, &child, level+1, recur, out)) ERROR_RX(false, "dump_dies child");
	if(!dwarf_siblingof(die, die) && !dump_dies(dw, die, level, recur, out)) ERROR_RX(false, "dump_dies sibling");
    }
    return true;
}

bool dwarf::dump_cus(Dwarf *dw, FILE *out)
{
    int dev;
    size_t header_sizep;
    Dwarf_Off off=0, next_off, abbrev_offsetp;
    uint8_t address_sizep, offset_sizep;
    do
    {
	dev=dwarf_nextcu(dw, off, &next_off,
			 &header_sizep, &abbrev_offsetp,
			 &address_sizep, &offset_sizep);
	fprintf(out, "CU at %llx, hsize=%x\n", off, header_sizep);

	Dwarf_Die die;
	if(dwarf_offdie(dw, off+header_sizep, &die) && !dump_dies(dw, &die, 1/*level*/, 1/*recur*/, out))
	    ERROR_RX(false, "dump_dies");

	off=next_off;
    }
    while(!dev);
    return true;
}

bool dwarf::dump(char *filename, char *out_filename)
{
    bool dev=true;

    // open file
    int fd;
    if((fd=open(filename, O_RDONLY))<0) {dev=false; ERROR("open: %s", strerror(errno));}
    else
    {
	// out file
	FILE *out=stdout;
	if(out_filename && *out_filename && !(out=fopen(out_filename, "w"))) {dev=false; ERROR("fopen: %s", strerror(errno));}
	else
	{
	    // dwarf begin
	    Dwarf *dw;
	    if(!(dw=dwarf_begin(fd, DWARF_C_READ))) {dev=false; ERROR("dwarf_init");}
	    else
	    {
		// dump CUs (Compilation Unit)
		if(!dump_cus(dw, out)) {dev=false; ERROR("dump_cus");}

		// dwarf end
		dwarf_end(dw);
	    }
	    // close out file
	    if(out!=stdout) fclose(out);
	}
	// close elf
	close(fd);
    }
    return dev;
}

void dwarf::analyze_dump_recur(FILE *out, int i, int level, int recur_child, int recur_type)
{
    char buf[DW_TAM_BUF];
    dwarf_base &b=base[i];

    // tag (+ selected + matched)
    fprintf(out, "%*s%s", level*5, "", entity_tag_string(b.type , buf));
    if(b.bit.selected) fprintf(out, " (selected)");
    if(b.bit.pattern_match) fprintf(out, " (matched %d)", b.bit.pattern_match);
    //if(b.level!=level) fprintf(out, " (error in level!)");
    fprintf(out, "\n");

    // offset
    fprintf(out, "%*s Offset    : @%d  (DW: %d)\n", level*5, "", i, b.off);

    // name
    if(b.i_name>=0) fprintf(out, "%*s Name      : %s\n", level*5, "", doc->string(b.i_name));

    // namespace
    if(b.i_namespace>=0 && b.type!=DW_TAG_formal_parameter)
	fprintf(out, "%*s Namespace : %s\n", level*5, "", doc->string(b.i_namespace));

    // attributes
    if(b.i_attr>=0) fprintf(out, "%*s Attribute : %s\n", level*5, "", doc->string(b.i_attr));

    // byte syze
    if(b.size>=0) fprintf(out, "%*s Byte size : %d\n", level*5, "", b.size);

    // file & lin
    if(b.i_source>=0) fprintf(out, "%*s File/Lin  : %s:%d\n", level*5, "", doc->string(b.i_source), b.line);

    // value meaning 1 (location, encoding, linkage, ...)
    switch(b.bit.value_meaning)
    {
    case DW_VALUE_NONE: break;
    case DW_VALUE_LOCATION:
	fprintf(out, "%*s Location  : %d\n", level*5, "", b.value.location);
	break;
    case DW_VALUE_ENCODING:
	fprintf(out, "%*s Encoding  : %s\n", level*5, "", entity_string(encoding_names, n_encoding_names, b.value.encoding));
	break;
    case DW_VALUE_LINKAGE:
	fprintf(out, "%*s Linkage   : %s\n", level*5, "", doc->string(b.value.linkage));
	break;
    case DW_VALUE_UPPER_BOUND:
	fprintf(out, "%*s UpperBound: %d\n", level*5, "", b.value.upper_bound);
	break;
    case DW_VALUE_VTABLE_LINK:
	fprintf(out, "%*s VTableLink: %s\n", level*5, "", doc->string(b.value.vtable_linkage));
	break;
    default:
	ERROR("TODO: value meaning 1");
    }

    // value meaning 2 (vtable...)
    switch(b.bit.value_meaning2)
    {
    case DW_VALUE2_NONE: break;
    case DW_VALUE2_VTABLE_POS:
	fprintf(out, "%*s VTable pos: %d\n", level*5, "", b.value2.vtable_pos);
	break;
    case DW_VALUE2_CONST_VALUE:
	fprintf(out, "%*s ConstValue: %d\n", level*5, "", b.value2.const_value);
	break;
    default:
	ERROR("TODO: value meaning 2");
    }

    // subtype
    if(b.i_subtype>=0)
    {
	fprintf(out, "%*s Type      : %d@\n", level*5, "", b.i_subtype);
	if(recur_type)
	    analyze_dump_recur(out, b.i_subtype, level+1, 0, recur_type-1);
    }

    // bits
    if(b.bit.declaration) fprintf(out, "%*s Declaratio: %d\n", level*5, "", b.bit.declaration);
    if(b.bit.artificial) fprintf(out, "%*s Artificial: %d\n", level*5, "", b.bit.artificial);
    if(b.bit.implementation) fprintf(out, "%*s Implementa: %d\n", level*5, "", b.bit.implementation);
    if(b.bit.ctor) fprintf(out, "%*s Ctor      : %d\n", level*5, "", b.bit.ctor);
    if(b.bit.dtor) fprintf(out, "%*s Dtor      : %d\n", level*5, "", b.bit.dtor);
    if(b.bit.virt) fprintf(out, "%*s Virtual   : %d\n", level*5, "", b.bit.virt);
    if(b.bit.volat) fprintf(out, "%*s Volatile  : %d\n", level*5, "", b.bit.volat);

    // i_function
    if(b.i_function>=0) fprintf(out, "%*s Function  : %s\n", level*5, "", doc->string(b.i_function));

    // childs
    if(recur_child)
	for(int j=0; j<b.n_child; j++)
	    analyze_dump_recur(out, b.i_child[j], level+1, recur_child-1, 0);
}

int dwarf::analyze_dump_debug(char *out_filename)
{
    return analyze_dump(out_filename, -1, 0, -1, 4);
}

int dwarf::analyze_dump(char *out_filename, int from, int initial_level, int recur_child, int recur_type)
{
    int dev=1;

    // out file
    FILE *out=stdout;
    if(out_filename && *out_filename && !(out=fopen(out_filename, "w"))) {dev=0; ERROR("fopen: %s", strerror(errno));}
    else
    {
	dev=analyze_dump_arch(out, from, initial_level, recur_child, recur_type);

	// close out file
	if(out!=stdout) fclose(out);
    }
    return dev;
}

int dwarf::analyze_dump_arch(FILE *arch, int from, int initial_level, int recur_child, int recur_type)
{
    int dev=1;

    if(arch!=stdout)
	fprintf(arch, "Base dump: from:%d level:%d recur_child:%d recur_type:%d n_bases:%d\n",
		from, initial_level, recur_child, recur_type, n_base);
    else fflush(stderr);
    if(from<0)
    {
	// dump all
	for(int i=0; i<root.n_child; i++)
	    analyze_dump_recur(arch, root.i_child[i], initial_level, recur_child, recur_type);
    }
    else analyze_dump_recur(arch, from, initial_level, recur_child, recur_type);
    return dev;
}

void dwarf::dump_stack(dwarf_base **stack, int n_stack)
{
    printf("Stack\n");
    for(int i=0; i<n_stack; i++)
	printf("\t%3d %s\n", i, stack[i]?(stack[i]->i_name>=0?doc->string(stack[i]->i_name):"<no name>"):"<no obj>");
}

int dwarf::search_by_offset(int offset)
{
    int ini=0, end=n_base;
    while(end>ini)
    {
	int mid=(ini+end)>>1;
	if(base[mid].off>=offset) end=mid; else ini=mid+1;
    }
    if(ini<n_base && base[ini].off==offset) return ini; else return -1;
}

int dwarf::search_add_string_check_artificial(char *name)
{
    // check artificial gcc names: TODO check all compilers
    if(name)
    {
	int n_name=strlen(name);
	if(n_name>=2 && name[0]=='.' && name[1]=='_') return -1; // '._' in the begining
    }

    return doc->search_add_string(name);
}

void dwarf::analyze_complete_declaration_with_definition_die(Dwarf_Die *die, dwarf_base *b, const char *cu_directory)
{
    // mark that this base has been updated by its definition
    b->bit.implementation=1;

    // name
    if(b->i_name<0) b->i_name=search_add_string_check_artificial((char*)dwarf_diename(die));

    // location
    if(b->bit.value_meaning!=DW_VALUE_LOCATION)
    {
	if(b->type==DW_TAG_variable && b->bit.value_meaning==DW_VALUE_LINKAGE)
	{
	    // this is a variable with linkage (the location information is not useful, linkage name is preferred)
	}
	else
	    analyze_add_location(die, b);
    }

    // file && line
    if(b->line<0 && b->i_source<0) analyze_add_file_line(die, b, cu_directory);

    // size
    if(b->size<0 && dwarf_hasattr(die, DW_AT_byte_size)) b->size=dwarf_bytesize(die);
}

bool dwarf::analyze_complete_declaration_with_definition(int i_base, Dwarf_Off *off, Dwarf_Die *die, Dwarf_Die **diep,
							 Dwarf_Die *stack, int *i_stack, const char *cu_directory,
							 int *&discard, int &n_discard, int &max_discard)
{
    // the base of the declaration
    dwarf_base *decl=&base[i_base];
    int i_child=0;

    // update root
    analyze_complete_declaration_with_definition_die(die, decl, cu_directory);

    // traverse all dwarf subtree
    Dwarf_Off old_off=*off;
    Dwarf_Die *old_diep=*diep, old_die, *old_diet=die;
    int old_i_stack=*i_stack, init_i_stack=*i_stack;
    memcpy(&old_die, die, sizeof(Dwarf_Die));
    while((die=traverse_dies(dw, off, die, diep, stack, i_stack, -1)))
    {
	if(*i_stack<=init_i_stack) break;

	// complete child
	if(dwarf_tag(die)==DW_TAG_formal_parameter && i_child<decl->n_child)
	{
	    dwarf_base *child=&base[decl->i_child[i_child]];
	    if(child->type==dwarf_tag(die)) analyze_complete_declaration_with_definition_die(die, child, cu_directory);
	    i_child++;
	}
	else if(dwarf_tag(die)==DW_TAG_structure_type || dwarf_tag(die)==DW_TAG_class_type ||
		dwarf_tag(die)==DW_TAG_union_type || dwarf_tag(die)==DW_TAG_typedef)
	{
	    // this is implementation internal structure/class declaration (not interesting)
	    // add to discarded list
	    int i_dis=util::inc_vector(discard, n_discard, max_discard, INC_MULTI_SPEC);
	    discard[i_dis]=dwarf_dieoffset(die);
	}

	// next iteration
	old_off=*off;
	old_diep=*diep;
	old_i_stack=*i_stack;
	memcpy(&old_die, die, sizeof(Dwarf_Die));
    }

    // go back one die
    *off=old_off;
    *diep=old_diep;
    *i_stack=old_i_stack;
    die=old_diet;
    memcpy(die, &old_die, sizeof(Dwarf_Die));
    return true;
}

bool dwarf::analyze_begin()
{
    // traverse for information
    Dwarf_Off off;
    Dwarf_Die diet, *diep, *stack, *die;
    int i_stack;
    unsigned offset=0;
    Dwarf_Attribute attr;
    const char *cu_directory=NULL;

    // type stack
    int base_stack[DW_MAX_DIE_STACK];
    memset(base_stack, 0, DW_MAX_DIE_STACK*sizeof(int));
    pointer_max=0;
    int discard_children=DW_MAX_DIE_STACK;

    // multi-specified types
    _multi_spec_ *multi_spec;
    int n_multi_spec, max_multi_spec;
    util::ctor_vector(multi_spec, n_multi_spec, max_multi_spec);

    // discarded types
    int *discard, n_discard, max_discard;
    util::ctor_vector(discard, n_discard, max_discard);

    // namespace
    int i_namespace_stack[DW_MAX_DIE_STACK+1];
    i_namespace_stack[0]=-1;

    // first pass: convert dies into dwarf_base tree
    traverse_dies_init(&off, &diep, &stack, &i_stack);
    while((die=traverse_dies(dw, &off, &diet, &diep, stack, &i_stack, -1)))
    {
	// discard children
	if(i_stack>discard_children) continue;
	else discard_children=DW_MAX_DIE_STACK;

	// check
	if(offset && dwarf_dieoffset(die)<=offset) ERROR_R0("internal offset");
	offset=dwarf_dieoffset(die);
	char *name=(char*)dwarf_diename(die);

	// CU directory
	if(!i_stack)
	{
	    if(dwarf_hasattr(die, DW_AT_comp_dir) && dwarf_attr(die, DW_AT_comp_dir, &attr)) cu_directory=dwarf_formstring(&attr);
	    else cu_directory=NULL;
	}

	// namespace
	if(name &&
	   (dwarf_tag(die)==DW_TAG_namespace || dwarf_tag(die)==DW_TAG_structure_type ||
	    dwarf_tag(die)==DW_TAG_class_type || dwarf_tag(die)==DW_TAG_union_type))
	{
	    // dealing with "::" namespace
	    if(!strcmp(name, "::"))
	    {
		// reset namespace
		i_namespace_stack[i_stack+1]=-1;
	    }
	    else
	    {
		// namespace increase
		if(i_namespace_stack[i_stack]>=0)
		{
		    // add
		    char namespc[DW_MAX_NAMESPACE];
		    snprintf(namespc, DW_MAX_NAMESPACE, "%s::%s", doc->string(i_namespace_stack[i_stack]), name);
		    i_namespace_stack[i_stack+1]=doc->search_add_string(namespc);
		}
		else
		    // create
		    i_namespace_stack[i_stack+1]=doc->search_add_string(name);
	    }
	}
	else
	    // no namespace increase
	    i_namespace_stack[i_stack+1]=i_namespace_stack[i_stack];

	// do not include namespace intermediate level
	if(dwarf_tag(die)==DW_TAG_namespace)
	{
	    base_stack[i_stack]=base_stack[i_stack-1];
	    if(i_stack>pointer_max) pointer_max=i_stack;

	    // references to namespaces must be discarded
	    int i_dis=util::inc_vector(discard, n_discard, max_discard, INC_MULTI_SPEC);
	    discard[i_dis]=dwarf_dieoffset(die);

	    continue;
	}

	// frame variables
	if(dwarf_tag(die)==DW_TAG_variable && i_stack && base[base_stack[i_stack-1]].type==DW_TAG_subprogram)
	{
	    continue; // not required
	}

	// lexical block
	if(dwarf_tag(die)==DW_TAG_lexical_block)
	{
	    discard_children=i_stack;
	    continue;
	}

	// bug (in at least g++3.4) with enumerator repetitions
	// remove them now
	if(dwarf_tag(die)==DW_TAG_enumerator)
	{
	    if(!i_stack) ERROR("enumerator at top level");
	    else
	    {
		int i_name;
		if((i_name=doc->search_string(name))>=0)
		{
		    // name exists in doc, check if there is repetition
		    dwarf_base *b=&base[base_stack[i_stack-1]];
		    int i;
		    for(i=0; i<b->n_child; i++)
		    {
			dwarf_base *child=&base[b->i_child[i]];
			if(child->i_name==i_name && child->type==DW_TAG_enumerator)
			    // this is an enumerator in the same enumeration type
			    // so its not required
			    break;
		    }
		    if(i<b->n_child) continue; // not required
		}
	    }
	}

	int i_new_base;
	dwarf_base *new_base;

	// implementation special case
	int is_spec;
	if((is_spec=dwarf_hasattr(die, DW_AT_specification)) || dwarf_hasattr(die, DW_AT_abstract_origin))
	{
	    // this base-tree is going to complete a specification base (just complete information on specification bases)
	    if((!is_spec || !dwarf_attr(die, DW_AT_specification, &attr)) &&
	       !dwarf_attr(die, DW_AT_abstract_origin, &attr))
		ERROR_R0("cannot obtain specification(%d)/abstrac_origin attribute 0x%x", is_spec, offset);

	    Dwarf_Die die_spec;
	    if(!dwarf_formref_die(&attr, &die_spec))
	    {
		ERROR("dwarf_formref for specification at %d 0x%x", offset, offset);
		fflush(stderr); fflush(stdout);
		dump_dies(dw, die, 1/*level*/, 0/*recur*/, stdout);
		analyze_dump();
		fflush(stdout);
		return false;
	    }
	    unsigned offset_spec=dwarf_dieoffset(&die_spec);
	    if((i_new_base=search_by_offset(offset_spec))<0)
	    {
		// no base with the specification/abstract origin found
		// try with the multi_spec list
		int i_multi;
		for(i_multi=0; i_multi<max_multi_spec; i_multi++)
		    if(multi_spec[i_multi].offset==(int)offset_spec) break;
		if(i_multi==max_multi_spec)
		{
		    // definitely not found
		    if(offset_spec>offset) continue; // its normal not to find it, still not read, can be bypassed (?)

		    ERROR("at 0x%x with %d bases cannot get specification base of offset: %d, 0x%x",
			  offset, n_base, offset_spec, offset_spec);
		    fflush(stderr); fflush(stdout);
		    dump_dies(dw, die, 1/*level*/, 0/*recur*/, stdout);
		    analyze_dump();
		    fflush(stdout);
		    return false;
		}
		else i_new_base=multi_spec[i_multi].i_base;
	    }

	    // save this multi-specification type
	    int i_multi=util::inc_vector(multi_spec, n_multi_spec, max_multi_spec, INC_MULTI_SPEC);
	    multi_spec[i_multi].offset=offset;
	    multi_spec[i_multi].i_base=i_new_base;

	    // check if this is completing a subprogram
	    if(dwarf_tag(die)==DW_TAG_subprogram || dwarf_tag(die)==DW_TAG_variable ||
	       dwarf_tag(die)==DW_TAG_inlined_subroutine)
	    {
		// just update info (same bases)
		if(!analyze_complete_declaration_with_definition(i_new_base, &off, &diet, &diep, stack, &i_stack, cu_directory,
								 discard, n_discard, max_discard))
		    ERROR_R0("cannot complete declaration with definition");
		continue;
	    }
	    else if(dwarf_tag(die)==DW_TAG_class_type || dwarf_tag(die)==DW_TAG_structure_type ||
		    dwarf_tag(die)==DW_TAG_union_type)
	    {
		// new bases will be added to this base
		// first, update root base
		analyze_complete_declaration_with_definition_die(&diet, &base[i_new_base], cu_directory);

		// update stack
		base_stack[i_stack]=i_new_base;
		if(i_stack>pointer_max) pointer_max=i_stack;

		// fix namespace
		if(base[i_new_base].i_namespace>=0)
		{
		    // add
		    char namespc[DW_MAX_NAMESPACE];
		    snprintf(namespc, DW_MAX_NAMESPACE, "%s::%s",
			     doc->string(base[i_new_base].i_namespace), doc->string(base[i_new_base].i_name));
		    i_namespace_stack[i_stack+1]=doc->search_add_string(namespc);
		}
		else
		    // create
		    i_namespace_stack[i_stack+1]=base[i_new_base].i_name;
		continue;
	    }

	    // error
	    ERROR("TODO: specificating %s at 0x%x", entity_tag_string(dwarf_tag(die)), offset);
	    continue;
	}
	else
	{
	    // fill base and add to list
	    i_new_base=util::inc_vector(base, n_base, max_base, INC_BASE);
	    new_base=&base[i_new_base];
	}

	// dwarf relation
	new_base->off=offset;

	// base structure
	//new_base->level=i_stack;
	dwarf_base *b;
	if(i_stack)
	{
	    b=&base[base_stack[i_stack-1]];
	    new_base->i_parent=base_stack[i_stack-1];
	    new_base->level=b->level+1;
	}
	else
	{
	    b=&root;
	    new_base->i_parent=-1;
	    new_base->level=0;
	}
	new_base->child_number=b->n_child;
	new_base->i_child=NULL;
	new_base->n_child=0;
	new_base->max_child=0;
	if(dwarf_hasattr(die, DW_AT_type))
	{
	    Dwarf_Die die_type;
	    if(!dwarf_attr(die, DW_AT_type, &attr) || !dwarf_formref_die(&attr, &die_type)) ERROR_R0("getting type");
	    new_base->i_subtype=dwarf_dieoffset(&die_type);
	}
	else if(dwarf_hasattr(die, DW_AT_import))
	{
	    Dwarf_Die die_import;
	    if(!dwarf_attr(die, DW_AT_import, &attr) || !dwarf_formref_die(&attr, &die_import)) ERROR_R0("getting import");
	    new_base->i_subtype=dwarf_dieoffset(&die_import);
	}
	else
	    new_base->i_subtype=-1;

	// attributes
	new_base->i_name=search_add_string_check_artificial((char*)name);
	new_base->type=dwarf_tag(die);
	if(!analyze_add_file_line(die, new_base, cu_directory)) return false;
	if(dwarf_hasattr(die, DW_AT_byte_size))
	    new_base->size=dwarf_bytesize(die);
	else
	    new_base->size=-1;
	new_base->i_namespace=i_namespace_stack[i_stack];
	new_base->i_attr=-1;

	// bits
	new_base->bit.all=0;
	bool flag;
	if(dwarf_hasattr(die, DW_AT_declaration) && dwarf_attr(die, DW_AT_declaration, &attr) && dwarf_formflag(&attr, &flag)!=-1)
	    new_base->bit.declaration=flag;
	if(dwarf_hasattr(die, DW_AT_artificial) && dwarf_attr(die, DW_AT_artificial, &attr) && dwarf_formflag(&attr, &flag)!=-1)
	    new_base->bit.artificial=flag;

	// location
	if(!analyze_add_location(die, new_base)) return false;

	// encoding
	if(dwarf_hasattr(die, DW_AT_encoding))
	{
	    Dwarf_Word uval;
	    if(dwarf_attr(die, DW_AT_encoding, &attr) && dwarf_formudata(&attr, &uval)!=-1)
	    {
		if(new_base->bit.value_meaning)
		    ERROR_R0("internal error: adding encoding, value occupied by %d", new_base->bit.value_meaning);
		new_base->bit.value_meaning=DW_VALUE_ENCODING;
		new_base->value.encoding=(int)uval;
	    }
	}

	// linkage
	if(dwarf_hasattr(die, DW_AT_MIPS_linkage_name))
	{
	    const char *str;
	    if(dwarf_attr(die, DW_AT_MIPS_linkage_name, &attr) && (str=dwarf_formstring(&attr)))
	    {
		if(new_base->bit.value_meaning &&
		   // if this is a variable (global) and value is LOCATION, it can safely be overwritten
		   (new_base->type!=DW_TAG_variable || new_base->bit.value_meaning!=DW_VALUE_LOCATION))
		    ERROR_R0("internal error: adding linkage, value occupied by %d", new_base->bit.value_meaning);
		new_base->bit.value_meaning=DW_VALUE_LINKAGE;
		new_base->value.encoding=doc->search_add_string(const_cast<char*>(str));
	    }
	}

	// upper_bound
	if(dwarf_hasattr(die, DW_AT_upper_bound))
	{
	    Dwarf_Word uval;
	    if(dwarf_attr(die, DW_AT_upper_bound, &attr) && dwarf_formudata(&attr, &uval)!=-1)
	    {
		if(new_base->bit.value_meaning)
		    ERROR_R0("internal error: adding upper_bound, value occupied by %d", new_base->bit.value_meaning);
		new_base->bit.value_meaning=DW_VALUE_UPPER_BOUND;
		new_base->value.upper_bound=(int)uval;
	    }
	}

	// const_value
	if(dwarf_hasattr(die, DW_AT_const_value))
	{
	    Dwarf_Sword val;
	    if(dwarf_attr(die, DW_AT_const_value, &attr) && dwarf_formsdata(&attr, &val)!=-1)
	    {
		if(new_base->bit.value_meaning2)
		{
		    dump_dies(dw, die, 1/*level*/, 0/*recur*/, stdout);
		    ERROR_R0("internal error: adding const_value, value occupied by %d", new_base->bit.value_meaning2);
		}
		new_base->bit.value_meaning2=DW_VALUE2_CONST_VALUE;
		new_base->value2.const_value=(int)val;
	    }
	}

	// ctor/dtor
	if(new_base->type==DW_TAG_subprogram && new_base->i_parent>=0 && new_base->i_name>=0)
	{
	    dwarf_base *parent=&base[new_base->i_parent];
	    if(parent->i_name>=0)
	    {
		char *func_name=doc->string(new_base->i_name);
		char *class_name=doc->string(parent->i_name);
		if(!string::strcmp_nospc(class_name, func_name, '<')) new_base->bit.ctor=1;
		if(func_name[0]=='~' && !string::strcmp_nospc(class_name, func_name+1, '<')) new_base->bit.dtor=1;
	    }
	}

	// virtuality
	if(dwarf_hasattr(die, DW_AT_virtuality) && dwarf_hasattr(die, DW_AT_vtable_elem_location))
	{
	    Dwarf_Word uval;
	    if(dwarf_attr(die, DW_AT_virtuality, &attr) && dwarf_formudata(&attr, &uval)!=-1)
	    {
		// the values of virtuality are 0:none, 1:virtual, 2:pure_virtual
		if(uval) new_base->bit.virt=1;
	    }

	    Dwarf_Op *expr;
	    unsigned int exprlen, pos;
	    if(dwarf_attr(die, DW_AT_vtable_elem_location, &attr) && dwarf_getlocation(&attr, &expr, &exprlen)!=-1)
	    {
		if((pos=addr_from_expression(expr, exprlen))!=MARK_BAD_ADDR)
		{
		    if(new_base->bit.value_meaning2)
			ERROR_R0("internal error: adding vtable_elem_location, value occupied by %d", new_base->bit.value_meaning2);
		    new_base->bit.value_meaning2=DW_VALUE2_VTABLE_POS;
		    new_base->value2.vtable_pos=pos;
		}
	    }
	}

	// manager function
	new_base->i_function=-1;

	// add to stack
	base_stack[i_stack]=i_new_base;
	if(i_stack>pointer_max) pointer_max=i_stack;

	// add to parent
	if(!b->add_child(i_new_base)) ERROR_R0("internal add child");
    }
    traverse_dies_finish(&stack);

    // second pass: type resolution
    for(int i=0; i<n_base; i++)
    {
	int i_subtype;
	if((i_subtype=base[i].i_subtype)>=0 && (base[i].i_subtype=search_by_offset(base[i].i_subtype))<0)
	{
	    // type is not in base structure, try in multi-spec vector
	    int im;
	    for(im=0; im<n_multi_spec; im++) if(multi_spec[im].offset==i_subtype) break;
	    if(im<n_multi_spec)
		// ok, found in multi_spec vector
		base[i].i_subtype=multi_spec[im].i_base;
	    else
	    {
		// check if it is in discarded types
		int id;
		for(id=0; id<n_discard; id++) if(discard[id]==i_subtype) break;
		if(id<n_discard)
		    // ok, found in discard vector
		    base[i].i_subtype=-1;
		else
		    ERROR_R0("internal reference type (cannot find %d 0x%x)\n"
			     "\t\tfrom base offset: %d 0x%x %s %s:%d\n"
			     "\t\tfrom parent offs: %d 0x%x %s %s:%d",
			     i_subtype, i_subtype, base[i].off, base[i].off,
			     doc->string(base[i].i_name), doc->string(base[i].i_source), base[i].line,
			     base[base[i].i_parent].off, base[base[i].i_parent].off,
			     doc->string(base[base[i].i_parent].i_name), doc->string(base[base[i].i_parent].i_source), base[base[i].i_parent].line);
	    }
	}
    }

    // third pass: modifiers
    for(int i=0; i<n_base; i++)
    {
	if(base[i].type==DW_TAG_volatile_type)
	{
	    if(base[i].i_subtype<0) {ERROR("modifier w/o subtype"); continue;}

	    // mark modifier in subtype
	    base[base[i].i_subtype].bit.volat=1;

	    // substitude bases pointing to this with this base subtype
	    for(int j=0; j<n_base; j++)
		if(base[j].i_subtype==i) base[j].i_subtype=base[i].i_subtype;
	}
    }

    // delete multi-spec vector
    util::ctor_vector(multi_spec, n_multi_spec, max_multi_spec);

    // delete discarded types
    util::dtor_vector(discard, n_discard, max_discard);

    return true;
}

bool dwarf::analyze_add_file_line(Dwarf_Die *die, dwarf_base *new_base, const char *cu_directory)
{
    if(dwarf_hasattr(die, DW_AT_decl_file))
    {
	const char *filename=dwarf_decl_file(die);
	if(filename)
	{
	    if(filename[0]=='/')
		new_base->i_source=doc->search_add_string((char*)filename);
	    else
	    {
		// add compilation unit directory to path
		if(!cu_directory) ERROR_R0("need to compose path but no cu_directory");

		char buffer[PATH_BUFFER];
		snprintf(buffer, PATH_BUFFER, "%s/%s", cu_directory, filename);
		new_base->i_source=doc->search_add_string(buffer);
	    }
	}
    }
    else
	new_base->i_source=-1;
    if(dwarf_hasattr(die, DW_AT_decl_line)) dwarf_decl_line(die, &new_base->line);
    else
	new_base->line=-1;
    return true;
}

bool dwarf::analyze_add_location(Dwarf_Die *die, dwarf_base *new_base)
{
    int loc=0, DMloc;
    if((DMloc=dwarf_hasattr(die, DW_AT_data_member_location)) || (loc=dwarf_hasattr(die, DW_AT_location)))
    {
	Dwarf_Attribute attr;
	Dwarf_Op *expr;
	unsigned int exprlen, addr, search_name;

	if(loc && DMloc) ERROR("warning: location and data_member_location");
	if(loc) search_name=DW_AT_location; else search_name=DW_AT_data_member_location;

	if(dwarf_attr(die, search_name, &attr) &&
	   //dwarf_getlocation(&attr, &expr, &exprlen)!=-1 && // commented due to a bug in elfutils at 07/08/09
	   dwarf_getlocation_addr(&attr, 0/*address*/, &expr, &exprlen, 1/*nlocs*/)!=-1 &&
	   (addr=addr_from_expression(expr, exprlen))!=MARK_BAD_ADDR)
	{
	    if(new_base->bit.value_meaning)
	    {
		// exception: LINKAGE is occuping the value
		// this is the case of global variables (is preferable to maintain
		// linkage so that symbol can be retrieved using dynamic linker)
		if(new_base->bit.value_meaning!=DW_VALUE_LINKAGE)
		{
		    ERROR("internal error: adding location, value occupied by %d", new_base->bit.value_meaning);
		    analyze_dump(NULL/*stdout*/, bp_index_from_addr(new_base)/*from*/, 1/*init_level*/, -1/*child*/, 2/*type*/);
		    return false;
		}
	    }
	    new_base->bit.value_meaning=DW_VALUE_LOCATION;
	    new_base->value.location=addr;
	}
	// do NOT show location errors on variables and parameters -> TODO
	else if(new_base->type!=DW_TAG_variable && new_base->type!=DW_TAG_formal_parameter)
	{
	    ERROR("location error: off:%7lld name:%s  type:%d  attr:%p  getlocation:%d  DM:%d", dwarf_dieoffset(die), doc->string(new_base->i_name), new_base->type,
		  dwarf_attr(die, search_name, &attr), dwarf_getlocation(&attr, &expr, &exprlen), DMloc);
	    fflush(stderr);
	    analyze_dump(NULL/*stdout*/, bp_index_from_addr(new_base)/*from*/, 1/*init_level*/, -1/*child*/, 2/*type*/);
	    fflush(stdout);
	}
    }
    return true;
}

void dwarf::analyze_dump_stats()
{
    fprintf(stderr, "#bases:%7d   #level1:%7d   doc size:%7d   depth:%2d\n", n_base, root.n_child, doc->get_n_doc(), pointer_max);
}

bool dwarf::analyze_remove_duplicates()
{
    // try to generate a list of first levers with no repetitions
    int *i_b, n_b, max_b; // sorted by type list of bases
    util::ctor_vector(i_b, n_b, max_b);

    // also make a substitution list for the removed entries
    int *subst=(int*)malloc(n_base*sizeof(int));
    for(int i=0; i<n_base; i++) subst[i]=i;

    for(int i=0; i<root.n_child; i++)
    {
	dwarf_base *cui=&base[root.i_child[i]];

	for(int ii=0; ii<cui->n_child; ii++)
	{
	    int found=0, bi=cui->i_child[ii];
	    dwarf_base *b=&base[bi];
	    int ini=0, end=n_b;

	    // TODO: there have been a compilation case where the same class was coded into both
	    //       DW_TAG_structure_type and DW_TAG_class_type. This is to solve this case
	    //       until a better solution is implemented!
	    if(b->type==DW_TAG_structure_type) b->type=DW_TAG_class_type;

	    int type=b->type;

	    // dicotomic search of type from 0 to n_b
	    while(end>ini)
	    {
		int mid=(ini+end)>>1;
		if(base[i_b[mid]].type>=type) end=mid; else ini=mid+1;
	    }
	    // dicotomic search of type+1 from ini to n_b
	    type++;
	    end=n_b;
	    int ini2=ini;
	    while(end>ini2)
	    {
		int mid=(ini2+end)>>1;
		if(base[i_b[mid]].type>=type) end=mid; else ini2=mid+1;
	    }
	    // dicotomic search of b->i_name in all of same type
	    end=ini2;
	    while(end>ini)
	    {
		int mid=(ini+end)>>1;
		if(base[i_b[mid]].i_name>=b->i_name) end=mid; else ini=mid+1;
	    }
	    // last linear search
	    while(ini<ini2 && base[i_b[ini]].i_name==b->i_name)
	    {
		// remove if duplicated
		if(equal_bases(bi, i_b[ini]))
		{
		    // remove base (bi) from hierarchy
		    equal_bases_subst(bi, i_b[ini], subst);
		    cui->i_child[ii]=cui->i_child[cui->n_child-1];
		    cui->n_child--;
		    base[cui->i_child[ii]].child_number=ii;
		    ii--;
		    found++;
		    break;
		}
		else
		{
		    // combine if required
		    dwarf_base *b2=&base[i_b[ini]];
		    if(b->i_name>=0 && b->i_namespace==b2->i_namespace &&
		       (b->type==DW_TAG_class_type || b->type==DW_TAG_structure_type) &&
		       (b->size<0 || b2->size<0 || b->size==b2->size) &&
		       (b->i_source<0 || b2->i_source<0 || b->i_source==b2->i_source) &&
		       (b->line<0 || b2->line<0 || b->line==b2->line))
		    {
			// same object distributed in multiple compilation units (CU)
			subst[bi]=i_b[ini];

			// remove childs of b with the same name of those of b2 (to avoid repetitions)
			// it's not necesary (and does not work) to use equal_bases()
			// TODO: select most descriptive childs (parameter names lost?)
			for(int k=0; k<b->n_child; k++)
			{
			    // loop over b2 childs to avoid repetitions
			    int l;
			    for(l=0; l<b2->n_child; l++)
			    {
				int iname[2]={base[b->i_child[k]].i_name, base[b2->i_child[l]].i_name};
				if(iname[0]==iname[1] ||
				   (iname[0]>=0 && iname[1]>=0 &&!strcmp(doc->string(iname[0]), doc->string(iname[1]))))
				{
				    // this child of b has the same name of one of b2: remove it
				    b->n_child--;
				    b->i_child[k]=b->i_child[b->n_child];
				    k--;
				    break;
				}
			    }
			}
			// move b children to b2
			for(int k=0; k<b->n_child; k++) b2->add_child(b->i_child[k]);

			// copy most descriptive params
			if(b->size>b2->size) b2->size=b->size;
			if(b->i_source>b2->i_source) b2->i_source=b->i_source;
			if(b->line>b2->line) b2->line=b->line;
			if(b->i_attr>b2->i_attr) b2->i_attr=b->i_attr;
			if(b->bit.value_meaning)
			{
			    if(b2->bit.value_meaning && b2->bit.value_meaning!=b->bit.value_meaning)
			    {
				ERROR("internal error: combine: adding value %d, value occupied by %d",
				      b->bit.value_meaning, b2->bit.value_meaning);
			    }
			    b2->bit.value_meaning=b->bit.value_meaning;
			    b2->value=b->value;
			}
			if(b->bit.value_meaning2)
			{
			    if(b2->bit.value_meaning2 && b2->bit.value_meaning2!=b->bit.value_meaning2)
			    {
				ERROR("internal error: combine: adding value2 %d, value occupied by %d",
				      b->bit.value_meaning2, b2->bit.value_meaning2);
			    }
			    b2->bit.value_meaning2=b->bit.value_meaning2;
			    b2->value2=b->value2;
			}

			// remove base b (bi)
			cui->i_child[ii]=cui->i_child[cui->n_child-1];
			cui->n_child--;
			base[cui->i_child[ii]].child_number=ii;
			ii--;

			// mark found
			found++;
		    }
		}
		ini++;
	    }
	    if(!found)
	    {
		util::inc_vector(i_b, n_b, max_b, INC_CHILD<<4);
		if(n_b-ini-1) memmove(&i_b[ini+1], &i_b[ini], (n_b-ini-1)*sizeof(int));
		i_b[ini]=bi;
	    }
	}
    }

    // re-create base list
    pointer_max=0;
    dwarf_base *new_base;
    int n_new_base, max_new_base;
    util::ctor_vector(new_base, n_new_base, max_new_base);
    int *old_to_new=(int*)malloc(n_base*sizeof(int));
    for(int i=0; i<n_base; i++) old_to_new[i]=-1;
    for(int i=0; i<n_b; i++)
    {
	int j;
	if((j=analyze_remove_duplicates_recur(i_b[i], new_base, n_new_base, max_new_base, subst, old_to_new))<0)
	    ERROR_R0("recreating list");
	new_base[j].i_parent=-1;
	new_base[j].child_number=i;
	i_b[i]=j;
    }

    // re-point subtypes
    for(int i=0; i<n_new_base; i++)
    {
	dwarf_base *b=&new_base[i];
	if(b->i_subtype>=0)
	{
	    int i_subtype=old_to_new[subst[b->i_subtype]];
	    if(i_subtype>=0)
	    {
		// change declaration structure_types by its complete structure_type (declaration=1 && implementation=0)
		if((new_base[i_subtype].type==DW_TAG_structure_type || new_base[i_subtype].type==DW_TAG_class_type ||
		    new_base[i_subtype].type==DW_TAG_union_type) &&
		   new_base[i_subtype].bit.declaration && !new_base[i_subtype].bit.implementation)
		{
		    if(!new_base[i_subtype].level)
		    {
			// search the complete type -> note that level 0 are sorted by TAG first and name later
			int j=i_subtype, found=0;
			while(j>=0 && new_base[j].i_name==new_base[i_subtype].i_name && new_base[j].type==new_base[i_subtype].type) j--;
			while(++j<n_new_base && new_base[j].i_name==new_base[i_subtype].i_name && new_base[j].type==new_base[i_subtype].type)
			{
			    if(!new_base[j].bit.declaration || new_base[j].bit.implementation)
			    {
				// found
				i_subtype=old_to_new[subst[b->i_subtype]]=j;
				found++;
				break;
			    }
			}
			// it's not an error to have only declaration
			//if(!found) ERROR("Internal: 1 complete declaration not found: %s", doc->string(new_base[i_subtype].i_name));
		    }
		    else
		    {
			// search in all bases
			int found=0;
			for(int j=0; j<n_new_base; j++)
			{
			    if(j==i_subtype || (new_base[j].bit.declaration && !new_base[j].bit.implementation)) continue;
			    if(new_base[j].i_name==new_base[i_subtype].i_name && new_base[j].type==new_base[i_subtype].type)
			    {
				// found
				i_subtype=old_to_new[subst[b->i_subtype]]=j;
				found++;
				break;
			    }
			}
			// it's not an error to have only declaration
			//if(!found) ERROR("Internal: 2 complete declaration not found: %s", doc->string(new_base[i_subtype].i_name));
		    }
		}
	    }
	    else
		ERROR("warning: subtype base lost: %6d %6d %6d  off:%7d", b->i_subtype, subst[b->i_subtype], i_subtype, base[b->i_subtype].off);
	    b->i_subtype=i_subtype;
	}
    }

    // free old bases and set new ones
    for(int i=0; i<n_base; i++) base[i].del_children();
    util::dtor_vector(base, n_base, max_base);
    base=new_base;
    n_base=n_new_base;
    max_base=max_new_base;

    // change root
    root.del_children();
    root.i_child=i_b;
    root.n_child=n_b;
    root.max_child=max_b;

    // free auxiliary vectors
    if(old_to_new) free(old_to_new);
    if(subst) free(subst);

    // restore pointers
    pointer_i=0;
    pointer_stack[0]=0;

#if 0
    // debug
    if(!check_base_structure()) ERROR_R0("internal, bad structure");
    if(!analyze_dump("/tmp/dw_no_duplicates.txt")) ERROR_R0("dumping dwarf structure");
#endif

    return true;
}

bool dwarf::analyze_remove_non_matched()
{
    // list of root childs
    int *i_b, n_b, max_b; // sorted by type list of bases
    util::ctor_vector(i_b, n_b, max_b);

    // new list of bases and mapping vector
    pointer_max=0;
    dwarf_base *new_base;
    int n_new_base, max_new_base;
    util::ctor_vector(new_base, n_new_base, max_new_base);
    int *old_to_new=(int*)malloc(n_base*sizeof(int));
    for(int i=0; i<n_base; i++) old_to_new[i]=-1;

    // loop over level 0
    for(int i=0; i<root.n_child; i++)
    {
	int ii=root.i_child[i];
	dwarf_base *b=&base[ii];
	if(b->bit.pattern_match)
	{
	    int k=util::inc_vector(i_b, n_b, max_b, INC_CHILD<<4);

	    int j;
	    if((j=analyze_remove_duplicates_recur(ii, new_base, n_new_base, max_new_base, NULL, old_to_new))<0)
		ERROR_R0("recreating list");
	    new_base[j].i_parent=-1;
	    new_base[j].child_number=k;
	    i_b[k]=j;
	}
	// in case of structures classes and unions, its necesary to check embedded types
	else if((b->type==DW_TAG_class_type || b->type==DW_TAG_structure_type || b->type==DW_TAG_union_type) &&
		b->n_child)
	{
	    int types[]={DW_TAG_class_type, DW_TAG_structure_type, DW_TAG_union_type, -1};
	    for(int i=0; types[i]>=0; i++)
	    {
		if(!analyze_goto(b->i_child[0]) || !search_new()) ERROR_R0("traversing");
		while(search_next_by_type(types[i]))
		{
		    dwarf_base *s=bp();
		    if(s->bit.pattern_match)
		    {
			// should include this into new list
			int k=util::inc_vector(i_b, n_b, max_b, INC_CHILD<<4);

			int j;
			if((j=analyze_remove_duplicates_recur(bp_index(), new_base, n_new_base, max_new_base, NULL, old_to_new))<0)
			    ERROR_R0("recreating list");
			new_base[j].i_parent=-1;
			new_base[j].child_number=k;
			i_b[k]=j;
		    }
		}
		search_end();
	    }
	}
    }

    // re-point subtypes
    for(int i=0; i<n_new_base; i++)
    {
	dwarf_base *b=&new_base[i];
	if(b->i_subtype>=0)
	{
	    int i_subtype=old_to_new[b->i_subtype];
	    if(i_subtype<0)
	    {
		fflush(stdout);
		ERROR("warning: subtype base lost: %6d  off:%7d", b->i_subtype, base[b->i_subtype].off);
		fflush(stderr);
		printf("previous type:\n");
		analyze_dump(NULL/*stdout*/, b->i_subtype/*from*/, 1/*init_level*/, -1/*child*/, 2/*type*/);
		fflush(stdout);
	    }
	    b->i_subtype=i_subtype;
	}
    }

    // free old bases and set new ones
    for(int i=0; i<n_base; i++) base[i].del_children();
    util::dtor_vector(base, n_base, max_base);
    base=new_base;
    n_base=n_new_base;
    max_base=max_new_base;

    // change root
    root.del_children();
    root.i_child=i_b;
    root.n_child=n_b;
    root.max_child=max_b;

    // free auxiliary vectors
    if(old_to_new) free(old_to_new);

    // restore pointers
    pointer_i=0;
    pointer_stack[0]=0;

    return true;
}

int dwarf::analyze_remove_duplicates_recur(int i, dwarf_base *&new_base, int &n_new_base, int &max_new_base, int *subst, int *old_to_new, int level, int all)
{
    if(subst) i=subst[i];
    if(old_to_new && old_to_new[i]!=-1) ERROR("warning repeated base");

    // fill base and add to list
    int i_new_base=util::inc_vector(new_base, n_new_base, max_new_base, INC_BASE);
    new_base[i_new_base].copy_attribs_from(&base[i]);
    new_base[i_new_base].level=level;
    new_base[i_new_base].i_child=NULL;
    new_base[i_new_base].n_child=0;
    new_base[i_new_base].max_child=0;

    new_base[i_new_base].off=base[i].off;
    new_base[i_new_base].i_function=base[i].i_function;

    if(level>pointer_max) pointer_max=level;

    // register mapping
    if(old_to_new) old_to_new[i]=i_new_base;

    // now the children
    for(int j=0; j<base[i].n_child; j++)
    {
	if(all || subst || base[base[i].i_child[j]].bit.pattern_match)
	{
	    int k;
	    if((k=analyze_remove_duplicates_recur(base[i].i_child[j], new_base, n_new_base, max_new_base, subst, old_to_new, level+1))<0)
		ERROR_R0("recreating list recur");
	    new_base[k].i_parent=i_new_base;
	    new_base[k].child_number=new_base[i_new_base].n_child; //j;
	    new_base[i_new_base].add_child(k);
	}
    }
    return i_new_base;
}

bool dwarf::analyze_resolve_imported_declarations_and_typedefs()
{
    for(int i=0; i<n_base; i++)
    {
	if(base[i].type==DW_TAG_imported_declaration || base[i].type==DW_TAG_typedef)
	{
	    // substitute this base for a copy of the imported declaration

	    // check type
	    int i_new_base;
	    if(base[i].i_subtype<0)
	    {
		if(base[i].type==DW_TAG_imported_declaration)
		{
		    ERROR("imported declaration base w/o subtype");
		    analyze_dump(NULL/*stdout*/, i/*from*/, 1/*init_level*/, -1/*child*/, 2/*type*/);
		    return false;
		}

		// void typedef
		i_new_base=-1; // case like "typedef void _IO_lock_t;"

		// remove from parent
		dwarf_base *parent;
		if(base[i].i_parent>=0) parent=&base[base[i].i_parent]; else parent=&root;
		parent->i_child[base[i].child_number]=parent->i_child[parent->n_child-1];
		parent->n_child--;
	    }
	    else
	    {
		// recreate tree
		i_new_base=analyze_remove_duplicates_recur(base[i].i_subtype, base, n_base, max_base, NULL, NULL, base[i].level, 1/*all*/);
		dwarf_base *new_base=&base[i_new_base];

		// set new base in structure (old imported_declaration base will still be in base list, but unreferenced)
		dwarf_base *parent;
		if(base[i].i_parent>=0) parent=&base[base[i].i_parent]; else parent=&root;
		parent->i_child[base[i].child_number]=i_new_base;
		new_base->i_parent=base[i].i_parent;
		new_base->child_number=base[i].child_number;

		// in case of typedef, inherit name from typedef and possibly source file and line of declaration
		if(base[i].type==DW_TAG_typedef)
		{
		    base[i_new_base].i_name=base[i].i_name;
		    if(base[i_new_base].i_source<0)
		    {
			base[i_new_base].i_source=base[i].i_source;
			base[i_new_base].line=base[i].line;
		    }
		}
	    }

	    // is there any i_subtype pointing to me
	    for(int j=0; j<n_base; j++)
		if(base[j].i_subtype==i) base[j].i_subtype=i_new_base;
	}
    }
    return true;
}

string_index *dwarf::analyze_reindex_doc()
{
    string_index *d=new string_index;
    for(int i=0; i<n_base; i++)
    {
	dwarf_base &b=base[i];
	if(b.i_name>=0) b.i_name=d->search_add_string(doc->string(b.i_name));
	if(b.i_source>=0) b.i_source=d->search_add_string(doc->string(b.i_source));
	if(b.i_namespace>=0) b.i_namespace=d->search_add_string(doc->string(b.i_namespace));
	if(b.i_attr>=0) b.i_attr=d->search_add_string(doc->string(b.i_attr));
	if(b.i_function>=0) b.i_function=d->search_add_string(doc->string(b.i_function));
	if(b.bit.value_meaning==DW_VALUE_LINKAGE && b.value.linkage>=0)
	    b.value.linkage=d->search_add_string(doc->string(b.value.linkage));
	if(b.bit.value_meaning==DW_VALUE_VTABLE_LINK && b.value.vtable_linkage>=0)
	    b.value.vtable_linkage=d->search_add_string(doc->string(b.value.vtable_linkage));
    }
    string_index *old=doc;
    doc=d;
    return old;
}

bool dwarf::analyze_check_complete_linkage(int verbo, char *filename_unresol, char *filename_symbols)
{
    FILE *arch=NULL, *arch_sym=NULL;
    if(verbo>1) arch=stdout;
    if(filename_unresol && !(arch=fopen(filename_unresol, "w")))
	MSG("%s: unresoluble linkage: %s", filename_unresol, strerror(errno));
    if(filename_symbols && !(arch_sym=fopen(filename_symbols, "w")))
	MSG("%s: ELF symbols: %s", filename_symbols, strerror(errno));

    bool dev=true;

    // get symbols from elf file
    string_index *symtab=new string_index;
    if(elf::get_symbols(elfname, symtab, 1/*demangle*/))
    {
	if(arch_sym)
	{
	    // debug symbols
	    symtab->dump(arch_sym);
	}

	for(int i=0; i<n_base; i++)
	{
	    dwarf_base &b=base[i];
	    if(b.type==DW_TAG_subprogram)
	    {
		if(b.i_name<0) {ERROR("warning subprogram with no name"); continue;}
		if(/*0 &&*/ b.bit.value_meaning==DW_VALUE_LINKAGE)
		{
		    // already has linkage so, only check its in symtab
		    if(b.value.linkage<0) {ERROR("warning invalid linkage index"); continue;}
		    if(symtab->search_prefix_string(doc->string(b.value.linkage))<0)
		    {
			// unresolubled symbol
			if(!b.bit.artificial)
			{
			    b.bit.pattern_match=0;
			    if(arch && arch!=stdout)
				fprintf(arch, "unresolubled symbol for %s subprogram: %s\n",
					doc->string(b.i_name), doc->string(b.value.linkage));
			    else if(arch)
				MSG("unresolubled symbol for %s subprogram: %s",
				    doc->string(b.i_name), doc->string(b.value.linkage));
			    dev=false;
			}
			b.bit.value_meaning=DW_VALUE_NONE;
			b.value.linkage=0;
		    }
		    // else symbol is correct and will be found in run-time
		}
		else
		{
		    // search linkage name for this name
		    if(!find_function_symbol(symtab, &base[i], arch))
		    {
			dev=false;
			b.bit.pattern_match=0;
		    }
		}
	    }
	    else if((b.type==DW_TAG_structure_type || b.type==DW_TAG_class_type) && b.i_name>=0)
	    {
		// search vtable mangled name
		for(int j=0; j<symtab->n_string(); j++)
		{
		    char *mangled=symtab->i_string(j);
		    char *demangled;
		    if(!(demangled=strchr(mangled, ELF_SEPARATOR_CHARACTER))) continue;
		    demangled++;
		    if(!memcmp(demangled, "vtable for ", 11) && !strcmp(doc->string(b.i_name), demangled+11))
		    {
			// vtable for this class
			if(b.bit.value_meaning)
			    ERROR("internal error: adding vtable linkage, value occupied by %d", b.bit.value_meaning);
			else
			{
			    *(demangled-1)=0;
			    b.bit.value_meaning=DW_VALUE_VTABLE_LINK;
			    b.value.vtable_linkage=doc->search_add_string(mangled);
			    *(demangled-1)=ELF_SEPARATOR_CHARACTER;
			}
		    }
		}
	    }
	}
    }
    else dev=false; // cannot get symbols from elf object

    if(arch && arch!=stdout) fclose(arch);
    if(symtab) delete symtab;
    return dev;
}

bool dwarf::find_function_symbol(string_index *symtab, dwarf_base *b, FILE *arch)
{
    bool dev=true;
    char *namespc=NULL;
    char *funcname=doc->string(b->i_name);
    int dtor=(funcname[0]=='~');

    // construct function or method name without parameters
    int n_symbol=strlen(funcname);
    char *symbol=NULL;

    // add namespace
    if(b->i_namespace>=0)
    {
	namespc=doc->string(b->i_namespace);
	n_symbol+=/*::*/2+strlen(namespc);
    }

    // create symbol
    symbol=(char*)malloc(n_symbol+1);
    if(namespc) snprintf(symbol, n_symbol+1, "%s::%s", namespc, funcname);
    else snprintf(symbol, n_symbol+1, "%s", funcname);

    // search without taking params into account
    string_index polymorph;
    for(int i=0; i<symtab->n_string(); i++)
    {
	char *str=symtab->i_string(i);
	if(namespc && !(str=strchr(str, ELF_SEPARATOR_CHARACTER))) continue; else str++;
	int n_str;
	if(!string::strncmp_nospc(symbol, str, n_symbol, &n_str) && (str[n_str]=='(' || str[n_str]=='<'))
	    polymorph.search_add_string(symtab->i_string(i));
    }

    if(!polymorph.n_string())
    {
	// funcname, namespc -> symbol
	if(arch && arch!=stdout) fprintf(arch, "Cannot find symbol for %s\n", symbol);
	else if(arch) MSG("Cannot find symbol for %s", symbol);
	dev=false;
    }
    else
    {
	// check against linkage strings (with params)
	int i;
	for(i=0; i<polymorph.n_string(); i++)
	{
	    // DTOR special case
	    /*
	      There may be multiple dtor functions with similar mangled names.
	      TODO: This needs further investigations, but it seems that D0Ev
	      ending dtors have integrated an object deallocating procedure, so
	      try to get D1Ev instead...
	    */
	    if(dtor && i<polymorph.n_string()-1 && strstr(polymorph.i_string(i), "D0Ev")) continue;

	    if(!namespc || match_prototype_params(polymorph.i_string(i), b))
	    {
		// this is the correct symbol for the function -> MATCH!
		// ERROR("Match: %s::%s -> %s", classname, funcname, polymorph.i_string(i));
		if(b->bit.value_meaning) {ERROR("internal: base aready has a value meaning, cannot add linkage"); dev=false;}
		else
		{
		    b->bit.value_meaning=DW_VALUE_LINKAGE;
		    b->value.linkage=doc->search_add_string(polymorph.i_string(i));
		}
		break;
	    }
	}
	if(i==polymorph.n_string())
	{
	    dev=false;

	    if(0)//b->bit.ctor)
	    {
		if(arch && arch!=stdout)
		    fprintf(arch, "Cannot resolve ctor {%s} linkage for {%s} class (poly=%d)\n", funcname, namespc, i);
		else if(arch)
		    MSG("Cannot resolve ctor {%s} linkage for {%s} class (poly=%d)", funcname, namespc, i);
	    }
	    else
	    {
		if(arch && arch!=stdout)
		    fprintf(arch, "Cannot resolve symbol for function %s in context %s (poly=%d)\n", funcname, namespc, i);
		else if(arch)
		    MSG("Cannot resolve symbol for function %s in context %s (poly=%d)", funcname, namespc, i);

		int j=0;
		for(i=0; i<symtab->n_string(); i++)
		{
		    char *str=symtab->i_string(i);
		    if(namespc && !(str=strchr(str, ELF_SEPARATOR_CHARACTER))) continue; else str++;
		    if(!string::strncmp_nospc(symbol, str, n_symbol)) ERROR("%2d: %s", j++, str);
		}

		fflush(stderr);
		analyze_dump(NULL/*stdout*/, bp_index_from_addr(b)/*from*/, 1/*init_level*/, -1/*child*/, 2/*type*/);
		fflush(stdout);
	    }
	}
    }

    if(symbol) free(symbol);
    return dev;
}

bool dwarf::match_prototype_params(char *proto, dwarf_base *b)
{
    bool dev=true;
    char *str;
    if((str=strchr(proto, ELF_SEPARATOR_CHARACTER))) proto=str+1; else return 1; // C style has no params
    *str=0;

    // extract params
    proto=string::regex(const_cast<char*>("\\((.*)\\)"), proto, 1/*group #*/);

    char **params;
    int n_params, max_params;
    util::ctor_vector(params, n_params, max_params);
    while(1)
    {
	// skip initial whitespace
	while(*proto==' ' || *proto=='\t') proto++;

	// add if there is another parameter
	if(*proto)
	{
	    int i=util::inc_vector(params, n_params, max_params, INC_PROTO_PARAMS);
	    params[i]=proto;
	} else break;

	// go to next param
	if(!(str=string::search(proto, const_cast<char*>(","), const_cast<char*>("\"\"()<>[]")))) break;
	*str=0;
	proto=str+1;
	while(*(--str)==' ' || *str=='\t') *str=0;
    }

    // now check params against base
    // count artificial params at start (this, size_t <- for destructors)
    int n_artificial=0;
    while(n_artificial<b->n_child && base[b->i_child[n_artificial]].bit.artificial) n_artificial++;

    // check number of params
    if(b->n_child!=n_params+n_artificial) dev=false;

    // check each param
    int i;
    for(i=0; dev && i<n_params; i++)
    {
	dwarf_base *param_base=&base[b->i_child[i+n_artificial]];
	if(param_base->i_subtype>=0)
	{
	    if(!match_string_type(params[i], &base[param_base->i_subtype])) break;
	}
	else
	{
	    ERROR("parameter has no type");
	    break;
	}
    }
    if(i!=n_params) dev=false;

    util::dtor_vector(params, n_params, max_params);
    return dev;
}

bool dwarf::match_string_type(char *str, dwarf_base *b)
{
    if(!str) ERROR_R0("internal: no string to match");

    dwarf_base *b_orig=b;
    int i_str=0, e_str=strlen(str), n;
    char *name;
    while(e_str>i_str)
    {
	switch(b->type)
	{
	case DW_TAG_pointer_type:
	    if(str[e_str-1]=='*') e_str--; else e_str=-1;
	    break;
	case DW_TAG_reference_type:
	    if(str[e_str-1]=='&') e_str--; //else e_str=-1;
	    break;
	case DW_TAG_const_type:
	    n=strlen("const");
	    if(e_str-i_str>=n && !strncmp(&str[e_str-n], "const", n)) e_str-=n; //else e_str=-1;
	    break;
	case DW_TAG_structure_type:
	case DW_TAG_class_type:
	case DW_TAG_base_type:
	    if((name=doc->string(b->i_name)))
	    {
		// remove name or try with other non-demangle-able types
		n=strlen(name);
		if(e_str-i_str>=n && !strncmp(&str[e_str-n], name, n)) e_str-=n;
		else
		{
		    // convert non-demangle-able base types into correct ones and try again
		    struct
		    {
			const char *undemangable;
			const char *substitute;
		    } types[]=
			  {
			      {"unsigned int", "int"}, // TODO: complete this list
			      {NULL, NULL}
			  };
		    int changed=0;
		    for(int i=0; types[i].undemangable; i++)
			if(!strcmp(types[i].undemangable, name))
			{
			    name=const_cast<char*>(types[i].substitute);
			    changed++;
			    break;
			}
		    if(changed)
		    {
			// try again with the substituted type
			n=strlen(name);
			if(e_str-i_str>=n && !strncmp(&str[e_str-n], name, n)) e_str-=n; else e_str=-1;
		    }
		    else e_str=-1;
		}

		if((name=doc->string(b->i_namespace)))
		{
		    // remove ::
		    if(e_str-i_str>=2 && !strncmp(&str[e_str-2], "::", 2)) e_str-=2; else e_str=-1;

		    // remove namespace
		    n=strlen(name);
		    if(e_str-i_str>=n && !strncmp(&str[e_str-n], name, n)) e_str-=n; else e_str=-1;
		}
	    }
	    else ERROR("class w/o name");
	    break;
	default:
	    ERROR("TODO: tag %s", entity_tag_string(b->type));
	    e_str=-1;
	    break;
	}

	// remove spaces before and after
	while(str[i_str]==' ' && i_str<e_str) i_str++;
	while(str[e_str-1]==' ' && i_str<e_str) e_str--;

	// debug
	// printf("["); for(int i=i_str; i<e_str; i++) printf("%c", str[i]); printf("]\n");

	// next type
	if(b->i_subtype<0)
	{
	    // check void?
	    break;
	}
	else b=&base[b->i_subtype];
    }

    if(e_str<0 || e_str>i_str)
    {
#if 1
	// error
	ERROR("cannot match [%s] with:", str);
	analyze_dump(NULL/*stdout*/, bp_index_from_addr(b_orig)/*from*/, 1/*init_level*/, -1/*child*/, 2/*type*/);
#endif
	return false;
    }
    return true;
}

bool dwarf::analyze_begin(char *filename)
{
    bool dev=true;

    // close any previous analysis
    analyze_end();

    // destruct previous analysis
    dtor();

    // save file
    if(elfname) elfname=(char*)realloc(elfname, 0);
    if(filename) elfname=strdup(filename);

    // open file
    if((fd=open(filename, O_RDONLY))<0) {dev=false; MSG("%s: %s", filename, strerror(errno));}
    else
    {
	// dwarf begin
	if(!(dw=dwarf_begin(fd, DWARF_C_READ))) {dev=false; MSG("%s: dwarf_begin", filename);}
	else
	{
	    if(!analyze_begin()) {dev=false; ERROR("analyze(Dwarf*)");}
	    else
	    {
		pointer_i=0;
		pointer_stack[0]=0;
	    }
	}
    }
    if(dw) {dwarf_end(dw); dw=NULL;}
    if(fd>=0) {close(fd); fd=-1;}
    return dev;
}

bool dwarf::analyze_end()
{
    if(elfname) elfname=(char*)realloc(elfname, 0);
    for(int i=0; i<n_base; i++) base[i].del_children();
    util::dtor_vector(base, n_base, max_base);
    root.del_children();
    pointer_i=pointer_max=-1;
    return true;
}

bool dwarf::equal_bases(int i, int j, int recur_level)
{
    if(i==j) return true;
    if(recur_level>pointer_max) return true;

    dwarf_base *bi=&base[i], *bj=&base[j];

    // check name, type and number of childs, source, bits
    if(bi->i_name!=bj->i_name || bi->type!=bj->type || bi->n_child!=bj->n_child ||
       bi->i_source!=bj->i_source || bi->line!=bj->line || bi->bit.all!=bj->bit.all ||
       bi->i_namespace!=bj->i_namespace ||
       bi->value.all!=bj->value.all || bi->value2.all!=bj->value2.all) return false;

    if(bi->i_source<0) // WARNING: see ** below
    {
	if(bi->i_name<0) // WARNING: see ** below
	{
	    // check subtypes
	    if(bi->i_subtype!=bj->i_subtype &&
	       (bi->i_subtype==-1 || bj->i_subtype==-1 || !equal_bases(bi->i_subtype, bj->i_subtype, recur_level+1))) return false;
	}

	// check childs
	for(int k=0; k<bi->n_child; k++)
	    if(bi->i_child[k]!=bj->i_child[k] && !equal_bases(bi->i_child[k], bj->i_child[k], recur_level+1))
	    {
		if(bi->i_source>=0 && bi->i_name>=0)
		{
		    ERROR("!= but same name and file: pos %7d and %7d, child %d", bi->off, bj->off, k);
		    // equal_bases(bi->i_child[k], bj->i_child[k], recur_level+1);
		}

		return false;
	    }
    }

    // **: there are situations when two structures may differ because one of
    //   : its member's subtype its only declared in one and defined in the other,
    //   : but both structures are the same

    return true;
}

void dwarf::equal_bases_subst(int i, int j, int *subst)
{
    if(i==j) return;
    subst[i]=j;

    dwarf_base *bi=&base[i], *bj=&base[j];

    for(int k=0; k<bi->n_child; k++)
	equal_bases_subst(bi->i_child[k], bj->i_child[k], subst);
}

int dwarf::analyze_get_level()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].level;
}

int dwarf::analyze_get_n_in_level()
{
    if(!check_pointer()) return -1;
    if(base[pointNC()].i_parent<0)
	return root.n_child;
    else
	return base[base[pointNC()].i_parent].n_child;
}

int dwarf::analyze_get_n_child()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].n_child;
}

bool dwarf::analyze_move_in_level(int i)
{
    if(!check_pointer() || i<0) return false;

    dwarf_base *b;
    if(base[pointNC()].i_parent<0) b=&root; else b=&base[base[pointNC()].i_parent];
    if(i>=b->n_child) return false;
    pointer_stack[pointer_i]=b->i_child[i];
    return true;
}

bool dwarf::analyze_move_next_in_level()
{
    if(!check_pointer()) return false;

    dwarf_base *b;
    if(base[pointNC()].i_parent<0) b=&root; else b=&base[base[pointNC()].i_parent];
    int i;
    if((i=base[pointNC()].child_number+1)>=b->n_child) return false;
    pointer_stack[pointer_i]=b->i_child[i];
    return true;
}

bool dwarf::analyze_down(int i)
{
    if(!check_pointer() || i<0 || i>=base[pointNC()].n_child) return false;
    pointer_stack[pointer_i]=base[pointNC()].i_child[i];
    return true;
}

bool dwarf::analyze_up()
{
    if(!check_pointer() || !base[pointNC()].level) return false;
    pointer_stack[pointer_i]=base[pointNC()].i_parent;
    return true;
}

bool dwarf::analyze_goto(int index)
{
    if(index>=0 && index<n_base) {pointer_stack[pointer_i]=index; return true;}
    return false;
}

bool dwarf::analyze_traverse()
{
    if(!check_pointer()) return false;

    // this base
    dwarf_base *b=&base[pointNC()];

    // go into child
    if(b->n_child) {pointer_stack[pointer_i]=b->i_child[0]; return true;}

    while(1)
    {
	// go to brother
	dwarf_base *p;
	if(b->i_parent<0) p=&root; else p=&base[b->i_parent];
	if(b->child_number<p->n_child-1) {pointer_stack[pointer_i]=p->i_child[b->child_number+1]; return true;}

	// go up
	if(!b->level) return false;
	pointer_stack[pointer_i]=b->i_parent;
	b=&base[pointNC()];
    }
}

void dwarf::analyze_dump_position()
{
    if(!check_pointer()) return;

    int stack[DW_MAX_DIE_STACK];
    int n_stack=0;

    dwarf_base *b=&base[pointNC()];
    while(1)
    {
	stack[n_stack++]=b->child_number;
	if(b->i_parent<0) break;
	b=&base[b->i_parent];
    }
    for(;n_stack>0; n_stack--) printf("%8d ", stack[n_stack-1]);
    printf("\n");
}

void dwarf::analyze_dump_inheritance_tree()
{
    if(!inheritance_new()) return;
    int level;
    while(inheritance_next(&level))
	printf("%*s%s\n", level*5, "", doc->string(base[pointNC()].i_name));
    inheritance_end();
}

bool dwarf::inheritance_new()
{
    if(!check_pointer() || (base[pointNC()].type!=DW_TAG_structure_type && base[pointNC()].type!=DW_TAG_class_type)) return false;
    inheritance_level=0;
    return true;
}

bool dwarf::inheritance_next(int *level)
{
    int traversed=0;
    while(1)
    {
	// check
	if(base[pointNC()].type!=DW_TAG_structure_type && base[pointNC()].type!=DW_TAG_class_type)
	    ERROR_RX(false, "internal, no structure_type");
	if(inheritance_level&1)
	    ERROR_RX(false, "internal, parity");

	if(traversed || !base[pointNC()].n_child)
	{
	    if(!inheritance_level) return false;
	    else
	    {
		// go up
		pointer_i--;
		inheritance_level--;
		search_just_init=0; // bypass the pointed inheritance base, aready checked
	    }
	}
	else
	{
	    // go into structure members
	    pointer_stack[pointer_i]=base[pointNC()].i_child[0];
	    if(!search_new()) ERROR_R0("internal");
	    inheritance_level++;
	}

	while(search_next_by_type(DW_TAG_inheritance))
	{
	    if(base[pointNC()].i_subtype>=0)
	    {
		// check
		if(!(inheritance_level&1)) ERROR_R0("internal, parity2");

		// go into type
		if(pointer_i==DW_MAX_P_STACK-1) ERROR_R0("pointer stack overflow");
		pointer_stack[pointer_i+1]=base[pointNC()].i_subtype;
		pointer_i++;
		if(level) *level=inheritance_level>>1;
		inheritance_level++;
		return true;
	    }
	}

	// go out structure members
	search_end();
	pointer_stack[pointer_i]=base[pointNC()].i_parent;
	inheritance_level--;
	traversed++;
    }
}

bool dwarf::inheritance_end()
{
    if(inheritance_level)
    {
	pointer_i-=inheritance_level;
	pointer_stack[pointer_i]=base[pointNC()].i_parent;
    }
    return true;
}

bool dwarf::search_new()
{
    if(!check_pointer()) return false;
    if(pointer_i==DW_MAX_P_STACK-1) ERROR_RX(false, "pointer stack overflow");
    pointer_stack[pointer_i+1]=pointNC();
    pointer_i++;
    search_just_init=1;
    return true;
}

void dwarf::search_end()
{
    if(!check_pointer()) return;
    if(!pointer_i) ERROR_R("usage");
    --pointer_i;
}

bool dwarf::search_next_by_name(char *name)
{
    if(!check_pointer() || !name) return false;

    while(1)
    {
	// common in all searchs
	if(search_just_init) search_just_init=0;
	else if(!analyze_traverse() || base[pointNC()].level<base[pointer_stack[pointer_i-1]].level) return false;

	if(base[pointNC()].i_name>=0 && !strcmp(name, doc->string(base[pointNC()].i_name))) return true;
    }
}

bool dwarf::search_next_by_name_type(char *name, int type)
{
    if(!check_pointer() || !name || type<0) return false;

    while(1)
    {
	// common in all searchs
	if(search_just_init) search_just_init=0;
	else if(!analyze_traverse() || base[pointNC()].level<base[pointer_stack[pointer_i-1]].level) return false;

	if(base[pointNC()].type==type && base[pointNC()].i_name>=0 && !strcmp(name, doc->string(base[pointNC()].i_name))) return true;
    }
}

bool dwarf::search_next_by_type(int type)
{
    if(!check_pointer() || type<0) return false;

    while(1)
    {
	// common in all searchs
	if(search_just_init) search_just_init=0;
	else if(!analyze_traverse() || base[pointNC()].level<base[pointer_stack[pointer_i-1]].level) return false;

	if(base[pointNC()].type==type) return true;
    }
}

bool dwarf::search_next_class_with_inheritance(char *inher)
{
    if(!check_pointer() || !inher) return false;

    while(1)
    {
	// common in all searchs
	if(search_just_init) search_just_init=0;
	else if(!analyze_traverse() || base[pointNC()].level<base[pointer_stack[pointer_i-1]].level) return false;

	if(base[pointNC()].type==DW_TAG_structure_type || base[pointNC()].type==DW_TAG_class_type)
	{
	    if(!inheritance_new()) ERROR_R0("internal");
	    //int level;
	    while(inheritance_next(/*&level*/))
		if(base[pointNC()].i_name>=0 && !strcmp(doc->string(base[pointNC()].i_name), inher))
		{
		    inheritance_end();
		    //ERROR("%d %s", level, base[pointNC()].get_name());
		    return true;
		}
	    inheritance_end();
	}
    }
}

char *dwarf::bp_name()
{
    if(!check_pointer()) return NULL;
    return doc->string(base[pointNC()].i_name);
}

int dwarf::bp_i_name()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].i_name;
}

int dwarf::bp_i_source_file()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].i_source;
}

int dwarf::bp_i_namespace()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].i_namespace;
}

int dwarf::bp_i_attr()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].i_attr;
}

char *dwarf::bp_type_name()
{
    if(!check_pointer()) return NULL;
    return entity_tag_string(base[pointNC()].type);
}

int dwarf::bp_type()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].type;
}

char *dwarf::bp_source_file()
{
    if(!check_pointer()) return NULL;
    return doc->string(base[pointNC()].i_source);
}

char *dwarf::bp_namespace()
{
    if(!check_pointer()) return NULL;
    return doc->string(base[pointNC()].i_namespace);
}

int dwarf::bp_source_line()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].line;
}

int dwarf::bp_source_column()
{
/*
    int col;
    if(!check_pointer()) return -1;
    if(dwarf_hasattr(&base[pointNC()].die, DW_AT_decl_column) && dwarf_decl_column(&base[pointNC()].die, &col)!=-1) return col;
*/
    return -1;
}

int dwarf::bp_byte_size()
{
    if(!check_pointer()) return -1;
    return base[pointNC()].size;
}

dwarf_base *dwarf::bp()
{
    if(!check_pointer()) return NULL;
    return &base[pointNC()];
}

dwarf_base *dwarf::bp_class_empty_ctor()
{
    if(!check_pointer()) return NULL;

    // check this is a structure/class
    dwarf_base *b=&base[pointNC()];
    if(b->type==DW_TAG_structure_type || b->type==DW_TAG_class_type)
    {
	for(int i=0; i<b->n_child; i++)
	{
	    dwarf_base *c=&base[b->i_child[i]];
	    if(c->bit.ctor)
	    {
		int j;
		for(j=0; j<c->n_child; j++) if(!base[c->i_child[j]].bit.artificial) break;
		if(j==c->n_child) return c;
	    }
	}
	return NULL;
    }
    else ERROR_R0("getting ctor in a non-class/non-structure");
}

dwarf_base *dwarf::bp_class_dtor()
{
    if(!check_pointer()) return NULL;

    // check this is a structure/class
    dwarf_base *b=&base[pointNC()];
    if(b->type==DW_TAG_structure_type || b->type==DW_TAG_class_type)
    {
	for(int i=0; i<b->n_child; i++)
	{
	    dwarf_base *c=&base[b->i_child[i]];
	    if(c->bit.dtor) return c;
	}
	return NULL;
    }
    else ERROR_R0("getting ctor in a non-class/non-structure");
}

void dwarf::traverse_dies_init(Dwarf_Off *off, Dwarf_Die **diep, Dwarf_Die **stack, int *i_stack)
{
    *diep=NULL;
    *off=0;
    *stack=(Dwarf_Die*)malloc(DW_MAX_DIE_STACK*sizeof(Dwarf_Die));
    *i_stack=0;
}

void dwarf::traverse_dies_finish(Dwarf_Die **stack)
{
    if(*stack) *stack=(Dwarf_Die*)realloc(*stack, 0);
}

Dwarf_Die *dwarf::traverse_dies(Dwarf *dw, Dwarf_Off *off, Dwarf_Die *die, Dwarf_Die **diep, Dwarf_Die *stack, int *i_stack, int tag_type)
{
    while(1)
    {
	// next DIE
	if(*diep)
	{
	    if(dwarf_haschildren(*diep))
	    {
		memcpy(&stack[*i_stack], *diep, sizeof(Dwarf_Die));
		if(++(*i_stack)==DW_MAX_DIE_STACK) ERROR_R0("stack overflow");

		if(dwarf_child(*diep, die)) ERROR_R0("dwarf_child");
	    }
	    else
	    {
		while(1)
		{
		    if(!dwarf_siblingof(*diep, die)) break; // next is sibling
		    else if(*i_stack) memcpy(die, &stack[--(*i_stack)], sizeof(Dwarf_Die));
		    else {*diep=NULL; break;}
		}
	    }
	}

	// next CU?
	while(!(*diep))
	{
	    size_t header_sizep;
	    Dwarf_Off next_off, abbrev_offsetp;
	    uint8_t address_sizep, offset_sizep;
	    if(dwarf_nextcu(dw, *off, &next_off,
			    &header_sizep, &abbrev_offsetp,
			    &address_sizep, &offset_sizep)) return NULL; // end

	    if(dwarf_offdie(dw, (*off)+header_sizep, die)) *diep=die;
	    (*off)=next_off;
	}

	// is die of correct type?
	if(dwarf_tag(*diep)==tag_type || tag_type<0) return *diep;
    }
}

bool dwarf::check_base_structure()
{
    int n_err=0;
    for(int i=0; i<n_base; i++)
    {
	dwarf_base &b=base[i];
	if(b.i_parent>=0)
	{
	    if(b.i_parent>=n_base) {n_err++; ERROR("base[%d] i_parent out of range", i);}
	    else
	    {
		dwarf_base *parent=&base[b.i_parent];
		if(b.child_number<0 || b.child_number>=parent->n_child) {n_err++; ERROR("base[%d] child_number out of range", i);}
		else if(parent->i_child[b.child_number]!=i) {n_err++; ERROR("base[%d]'s parent[%d] relation mismatch", i, b.i_parent);}
	    }
	}
	else if(b.i_parent==-1)
	{
	    if(b.child_number<0 || b.child_number>=root.n_child) {n_err++; ERROR("top level base[%d] child number out of range", i);}
	    else if(root.i_child[b.child_number]!=i) {n_err++; ERROR("top level base[%d]'s root relation mismatch: %d!=%d", i, root.i_child[b.child_number], i);}
	}
	else {n_err++; ERROR("base[%d] i_parent <-1", i);}

	for(int j=0; j<b.n_child; j++)
	{
	    if(b.i_child[j]<0 || b.i_child[j]>=n_base) {n_err++; ERROR("child %d of base[%d] out of range", j, i);}
	    else if(base[b.i_child[j]].i_parent!=i) {n_err++; ERROR("child %d of base[%d]'s parent is not %d", j, i, i);}
	}

	if(b.i_subtype<-1 || b.i_subtype>=n_base) {n_err++; ERROR("subtype of base[%d] out of range 0<=%d<%d", i, b.i_subtype, n_base);}
    }
    return (n_err==0);
}
